能,但仅限SQL Server 2016及以上版本且兼容级别≥130;低于该版本或级别会报错“Invalid object name 'STRING_SPLIT'”,需先检查并执行ALTER DATABASE SET COMPATIBILITY_LEVEL = 130升级。

STRING_SPLIT 函数在存储过程里能直接用吗?
能,但仅限 SQL Server 2016 及以上版本,且数据库兼容级别 ≥ 130。低于这个版本会报错 Invalid object name 'STRING_SPLIT'。如果遇到这个错误,先查 SELECT COMPATIBILITY_LEVEL FROM sys.databases WHERE name = DB_NAME(),再用 ALTER DATABASE [db_name] SET COMPATIBILITY_LEVEL = 130 升级(注意测试影响)。
怎么把逗号字符串传进 STRING_SPLIT 并 JOIN 到主表?
STRING_SPLIT 返回的是单列 value 表,不能直接用在 WHERE IN 子句里做“隐式转换”。常见错误是写成 WHERE id IN (SELECT value FROM STRING_SPLIT(@csv, ','))——这看似可行,但若 @csv 为空或全是空格,STRING_SPLIT 返回零行,整个 IN 判断变成空集,逻辑可能意外失效。
更稳妥的做法是显式 JOIN 或 EXISTS:
SELECT t.* FROM dbo.orders t INNER JOIN STRING_SPLIT(@order_ids, ',') s ON t.id = TRY_CAST(s.value AS INT);
关键点:
-
TRY_CAST防止非数字字符串导致运行时错误 - 必须用
INNER JOIN或EXISTS,避免空输入引发逻辑漏洞 -
STRING_SPLIT不保证顺序,如需按原 CSV 位置排序,得加WITH ORDINAL(SQL Server 2022+)或自行加序号临时表
为什么用 STRING_SPLIT 后查询变慢?
因为 STRING_SPLIT 返回的是内存表,没有统计信息,优化器常误估行数,导致 JOIN 时选错执行计划(比如该走哈希连接却走了嵌套循环)。尤其当 @csv 很长(上千项)时更明显。
可选缓解方式:
- 对小数据量(OPTION (RECOMPILE) 让每次编译都基于实际参数重估
- 对大数据量,改用数字辅助表或递归 CTE 预生成拆分结果(可控性更强)
- 避免在 WHERE 子句里嵌套
STRING_SPLIT多次调用,提取到 CTE 或临时表复用
替代方案:兼容老版本或需要去重/清洗怎么办?
如果用的是 SQL Server 2014 或更低版本,STRING_SPLIT 不可用,得用自定义拆分函数(如基于 WHILE + SUBSTRING 的 TVF),但性能通常更差。另外,STRING_SPLIT 不自动 trim 空格、不处理重复值、也不过滤空字符串——比如 '1,,2, 3 ' 会返回 '1'、''、'2'、' 3 ' 四行。
安全写法要手动清理:
SELECT DISTINCT LTRIM(RTRIM(s.value)) AS item FROM STRING_SPLIT(@input, ',') s WHERE NULLIF(LTRIM(RTRIM(s.value)), '') IS NOT NULL;
真正上线前,一定拿含空格、空项、重复值、超长项的测试数据跑一遍——这些边界情况最容易在生产环境突然暴露。

















