stuff函数参数为stuff(string, start, length, replacement),start从1开始计数,length为删除字符数(可为0),start超界返回原串、为负或0则返回null,length超长则删至末尾;常与for xml path配合去首分隔符,但sql server 2017+推荐string_agg;定位第n次出现字符需嵌套charindex;在where或join中滥用会导致索引失效和性能下降。

STUFF函数的参数顺序和起始位置容易搞错
SQL Server 的 STUFF 函数不是“删除某字符”,而是“从指定位置删掉指定长度,再插入一段字符串”。它的签名是 STUFF(string, start, length, replacement) —— 第二个参数 start 是**从 1 开始计数**,不是 0;第三个参数 length 是要删掉的字符个数,可以为 0(此时相当于纯插入,不删任何东西)。
常见错误是把 start 当成索引 0 起算,或误以为 length 是目标字符的长度(比如想删掉一个逗号就写 length = 1,结果删对了,但若没注意 start 偏移,就会插歪)。
- 如果
start超出原字符串长度,返回原字符串(不报错) - 如果
start为负数或 0,STUFF返回NULL -
length若大于剩余字符数,就删到末尾为止,不会报错
用STUFF拼接多行值时替代XML PATH的坑
很多人用 STUFF 配合 FOR XML PATH('') 实现行转列拼接,例如去重合并标签。但这里的关键不是 STUFF 本身,而是它如何配合子查询“削掉开头多余的分隔符”。
典型写法:STUFF((SELECT ',' + name FROM users FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') —— 注意:第一个 1 是从位置 1 开始删,第二个 1 是删 1 个字符(即开头那个多余的逗号)。
一款AI工具,主要用于管理 OpenClaw 所使用的来自 OpenRouter 的免费 AI 模型。自动按质量对模型进行排序,配置回退机制以应对速率限制,并更新 opencla...,适合需要提升相关任务效率的用户。
- 必须用
.value('.', 'NVARCHAR(MAX)')把 XML 结果转成字符串,否则可能含转义字符(如&) - 如果子查询结果为空,
STUFF返回NULL,需用ISNULL(..., '')包裹 - SQL Server 2017+ 更推荐用
STRING_AGG,STUFF+FOR XML是兼容旧版本的权宜之计
想用STUFF做“替换第N个逗号”这类操作?先确认是否真需要
STUFF 本身不识别字符内容,只认位置。所以“把第三个逗号换成分号”这种需求,不能直接靠一次 STUFF 完成,得先定位——通常得嵌套 CHARINDEX 或用递归 CTE 找第 N 次出现的位置。
例如找第二个逗号位置:CHARINDEX(',', col, CHARINDEX(',', col) + 1),再把这个结果传给 STUFF 的 start 参数。
- 嵌套过深会让语句难读难调,尤其当目标字符重复频繁时,
CHARINDEX容易定位错位 - 如果只是想统一替换所有某字符,
REPLACE更快更安全 - 真正适合
STUFF的场景是:已知精确偏移(如固定格式日志中第 12–15 位替换成新值)
在WHERE或JOIN条件里滥用STUFF会导致性能暴跌
STUFF 是标量函数,用在 WHERE 条件里会让 SQL Server 无法有效利用索引——即使你对原字段建了索引,一旦套上 STUFF(col, ...),优化器大概率走全表扫描。
比如写 WHERE STUFF(phone, 4, 0, '-') = '138-1234-5678',不如提前在应用层或持久化计算列里处理好带分隔符的格式,再查。
- 如果必须用,考虑加计算列并持久化、建索引:
ALTER TABLE t ADD phone_formatted AS STUFF(phone, 4, 0, '-') PERSISTED - 避免在 JOIN ON 中使用
STUFF,哪怕两边都用,也极大概率导致嵌套循环而非哈希匹配 - 字符串越长、调用越频繁,CPU 消耗越明显,尤其在大表聚合时
STUFF 的前提,是清楚它只操作“位置”,不理解“语义”;所有看似聪明的动态定位逻辑,最终都得靠 CHARINDEX、LEN 这些辅助函数撑着——而这些函数本身没有索引加速能力。










