STRING_SPLIT在SQL Server 2016+中需清洗空值、TRIM并显式编号保序;2016–2019须用ROW_NUMBER(),2022+可用ordinal参数;直接嵌套WHERE中会导致无序、空项、性能退化,应先存入带索引临时表。

SQL Server 2016+ 直接用 STRING_SPLIT 最省事,但必须清洗空值、TRIM 和显式编号保序;MySQL 没内置函数,得靠循环 + SUBSTRING_INDEX + 临时表;老版本 SQL Server(如 2008)只能手写 WHILE + CHARINDEX 拆分——选错方案会导致查询卡死或结果错序。
SQL Server 2016+:用 STRING_SPLIT 存入临时表的正确姿势
直接在 WHERE 里嵌套 STRING_SPLIT 是常见错误,它不保证顺序、不自动去空、不支持索引下推,容易拖垮性能。
- 必须先存进带索引的临时表:
SELECT TRIM(value) AS val INTO #split_ids FROM STRING_SPLIT(@ids, ',') WHERE TRIM(value) != '',再CREATE INDEX IX_val ON #split_ids(val) - 2016–2019 版本需手动加序号:
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn, TRIM(value) AS val ...,否则JOIN或IN时顺序不可靠 - 2022+ 可用
ordinal参数简化:SELECT value, ordinal FROM STRING_SPLIT(@ids, ',', 1),但注意该参数默认为 0(不返回序号) - 别用
IN (SELECT value FROM STRING_SPLIT(...))做过滤——执行计划常转成 Nested Loop,大数据量时极慢
MySQL:用存储过程 + SUBSTRING_INDEX 拆分并写入临时表
MySQL 没等价于 STRING_SPLIT 的函数,REPLACE+XML 方案在高版本已禁用,唯一稳定方式是循环提取。
- 先算分隔符个数:
SET lenstr = LENGTH(s_str) - LENGTH(REPLACE(s_str, s_split, '')) + 1 - 每次用
SUBSTRING_INDEX配合REVERSE提取末段(避免正向截取时边界错位):REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING_INDEX(s_str, s_split, i)), s_split, 1)) - 务必用
CREATE TEMPORARY TABLE(不是#开头的局部表),否则并发调用会冲突 - 循环前加
DROP TEMPORARY TABLE IF EXISTS tx_strlist,防止上一次异常退出残留表结构
SQL Server 2008/2012:手写 WHILE + CHARINDEX 拆分逻辑
这个写法现在仍常见于遗留系统,但极易漏掉边界处理,导致最后一条数据丢失或空字符串入库。
- 初始化时
@n = 1,@m = CHARINDEX(',', @str),进入循环前要检查@m > 0,否则跳过整个循环 - 截取子串用
SUBSTRING(@str, @n, @m - @n),但当@m = 0(即无更多逗号)时,必须补一手:SUBSTRING(@str, @n, LEN(@str) - @n + 1)获取末段 - 插入前必须
IF LEN(@id) > 0判断,否则空字符串会污染后续IN查询结果 - 不要在循环里反复查表(如每拆一个 ID 就
INSERT ... SELECT),应先拼进临时表再统一 JOIN,否则 I/O 放大数倍
通用避坑点:临时表生命周期与查询安全
所有方案都依赖临时表,但它的作用域和清理逻辑常被忽略,尤其在嵌套存储过程或事务中。
-
#tb是会话级局部临时表,存储过程结束后自动销毁;##tb是全局临时表,需显式DROP TABLE ##tb,否则可能被其他会话误读 - 如果拆分后要用于
JOIN,别用SELECT * FROM #split_ids WHERE val IN (SELECT val FROM #split_ids)这种自关联——SQL Server 可能选错执行计划,改用EXISTS或强制哈希连接 - 传入字符串含单引号(如
O'Connor)时,STRING_SPLIT不报错但后续动态 SQL 会炸,必须提前REPLACE(@ids, '''', '''''')转义 - 最大长度限制:SQL Server
NVARCHAR(MAX)实际能拆的字符数受内存和递归深度影响,超 8000 字符建议在应用层切分

















