STUFF函数从指定位置删除指定长度字符后插入新字符串,参数为STUFF(string,start,length,replacement),start从1开始,length为0时仅插入,超长则删至末尾。

STUFF函数的基本用法和参数含义
STUFF 不是替换任意位置的子串,而是「从指定位置删除指定长度字符,再插入新字符串」。它的签名是 STUFF(string, start, length, replacement):第一个参数是源字符串,start 是起始位置(从 1 开始计数),length 是要删掉的字符数,replacement 是插入的内容。
常见误解是把它当 REPLACE 用——比如想把第 3 位开始的 2 个字符换成 "XX",结果写成 STUFF(col, 3, 2, 'XX') 看似合理,但要注意:length 为 0 时不会删字符,只做插入;length 超出剩余长度时,会删到末尾为止,不会报错。
示例:
SELECT STUFF('abcdef', 3, 2, 'XY'); -- 返回 'abXYef'(删掉 'cd',插入 'XY')处理 NULL 或空字符串时的坑
如果任意一个参数为 NULL,整个 STUFF 结果就是 NULL。这在拼接字段或动态构造字符串时特别容易踩中。
- 源字符串为
NULL→ 结果为NULL,哪怕start和length都合法 -
start小于 1 或大于源字符串长度 + 1 → 返回原字符串(不报错,但行为易被忽略) -
length为负数 → 报错:Argument data type int is invalid for argument 3 of stuff function
安全写法建议加 ISNULL 或 COALESCE:
SELECT STUFF(ISNULL(col, ''), 5, 3, '***') FROM table;
用STUFF实现逗号分隔字符串拼接(经典场景)
虽然这不是“替换指定长度”,但它是 STUFF 最高频的实战用途——配合 FOR XML PATH 去掉开头多余的逗号。
典型写法:
SELECT STUFF((
SELECT ',' + name
FROM users u2
WHERE u2.group_id = u1.group_id
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS names
FROM users u1
GROUP BY u1.group_id;这里 STUFF(..., 1, 1, '') 的作用是:删掉第一个字符(即开头多出来的逗号),不插入任何内容。关键点在于:
-
FOR XML PATH('')拼出的是,Alice,Bob,Charlie这种带前导逗号的字符串 -
STUFF的length必须是 1,不能写成 0(否则逗号保留) -
TYPE).value(...)是为了正确处理特殊字符(如
和REPLACE、SUBSTRING组合使用的边界情况
真正需要“替换指定长度”逻辑时,STUFF 往往得搭配 CHARINDEX 或 PATINDEX 定位起始点,否则无法动态找位置。
例如:把邮箱 @ 符号后域名部分替换成 'example.com':
SELECT STUFF(email, CHARINDEX('@', email), LEN(email) - CHARINDEX('@', email) + 1, '@example.com')
FROM users
WHERE email LIKE '%@%';注意几个易错点:
-
CHARINDEX找不到时返回 0,会导致STUFF的start=0→ 视为 1 处理,可能误改开头 - 计算
length时漏加 1,会少删掉 @ 符号本身 - 没加
WHERE过滤无 @ 的记录,会导致CHARINDEX返回 0,进而让STUFF行为偏离预期
复杂点永远在定位逻辑里,而不是 STUFF 本身。它只是执行者,不是侦探。

















