SQL Server字符串函数实战:截取、拆分、拼接与性能避坑指南

发布时间:2026/10/17 5:02:59
SQL Server字符串函数实战:截取、拆分、拼接与性能避坑指南
经常有同学问我SQL Server里字符串处理到底要学哪些函数是不是把网上的函数清单背一遍就够用了我的回答一直是——函数名可以查但“什么时候用哪个、为什么用这个、用的时候有什么坑”才是真正值钱的经验。本章围绕字符串函数按实际开发场景重新梳理一遍把遇到过的问题和验证过的方法一并写出来。适用人群很明确刚接触SQL Server、写过一些查询但总觉得字符串处理没底的同学以及有几年经验、想系统查漏补缺的开发。看懂这一章日常的截取、匹配、拆分、聚合拼接基本都能自己搞定遇到性能问题也知道往哪个方向排查。1. 字符串函数在SQL开发中的真实位置1.1 为什么字符串函数值得单独用一整章来讲先聊一个很现实的问题一张业务表里字符串字段往往占了大头。用户姓名、手机号、邮箱、地址、备注、状态标记、编号几乎都是字符型。应用层拿到这些数据可能要拼接展示可能要按规则截取可能要模糊搜索也可能要根据某个分隔符把一列拆成多行。这些需求背后全部要落到T-SQL的字符串函数上。很多初学者以为字符串函数就是“截一截、拼一拼”其实它覆盖的远不止这些。我归纳了六类功能取长度、定位、截取、拼接替换、大小写与去空格、格式化转换。在较新的版本里还加入了拆分与聚合这类集合作业能力。理解了这个分类你在面对一个具体需求时才能快速定位该查哪一类函数。还有一个容易被忽略的点字符串函数是SQL Server执行计划里的常客。一个写法不同可能让查询从索引查找退化成全表扫描一个函数用错可能导致隐式转换、排序规则冲突甚至让查询直接报错。所以这一章不仅要讲函数怎么用还要讲怎么用好、怎么避坑。1.2 读这一章前需要具备的基础字符串函数本身不难但有几个前置概念建议先温习一下否则后面有些坑看不明白数据类型与存储方式。SQL Server里 char、varchar、nchar、nvarchar 这几个类型的行为不一样。char/nchar定长varchar/nvarchar变长n前缀表示使用Unicode编码。字符串函数对这两类数据的处理结果也有细微差异比如 LEN 函数对尾随空格的计数方式就和中国人的直觉不太一样后面会详细说。排序规则。数据库默认的排序规则Collation会影响字符串比较和排序结果。比如在中文环境下一个汉字按拼音排序还是按笔画排序取决于排序规则设置。字符串函数里的 CHARINDEX、LIKE、PATINDEX 等定位匹配操作都受排序规则影响。曾经我排查过一个“明明字符相同却匹配不上”的问题最后定位到两列数据的排序规则不同字符串比较时报了“无法解决排序规则冲突”的错误。索引与查询优化基础。函数作用在列上通常会导致索引失效。这个规律在字符串函数中同样适用比如 WHERE LEFT(name, 1) 张 这个写法就没法直接走 name 列上的索引。这类问题放到后面性能实践部分细聊。2. 高频基础函数逐个拆解长度、定位、截取2.1 长度计算LEN 与 DATALENGTH 的区别先拿两个最基础的函数开刀。LEN 返回字符数DATALENGTH 返回字节数。对英文字母和数字来说一个字符占1个字节两者结果相同但对汉字来说一个字符在Unicode下占2个字节LEN 算出来是字符数DATALENGTH 算出来是字节数结果会差一倍。实际开发中定义表字段长度时需要知道字节占用校验字符串是否超长时会用 DATALENGTH。而统计用户输入的字符个数、计算字符串显示宽度时通常用 LEN。举一个我经历过的例子某个保存用户昵称的字段定义为 nvarchar(50)但看起来“50”指的是字符数。如果用户输入了25个汉字LEN 返回25DATALENGTH 返回50两者都能对上“50”的上限。但如果字段是 varchar(50)同一个字符串 LEN 返回25DATALENGTH 也是25而25个汉字在GBK编码下实际要占50个字节这时 varchar(50) 强制用单字节存储就可能会截断或者报错。建议开发表结构时有中文需求优先用 nvarchar。这里有一个 LEN 的关键细节LEN 不计算尾随空格。比如字符串 SQL Server 后面带3个空格LEN 返回10而不是13。但 DATALENGTH 会把这3个空格算进去。这个差异常导致数据比对时出现“看起来相等、实际却不相等”的情况也是很多数据一致性问题的根源。2.2 定位查找CHARINDEX 与 PATINDEX 的选择逻辑CHARINDEX 用于查找一个字符串在另一个字符串中的起始位置。如果找不到返回0。它的基本用法是 CHARINDEX(要找的字符串, 原字符串, [起始位置])。第三个参数可选不写时从第一个字符开始找。返回的位置从1计数这一点和很多编程语言的索引从0开始不同刚切换过来的人容易犯晕。PATINDEX 的用法稍微复杂一点它支持在查找模式里使用通配符。可以这样理解CHARINDEX 只能找“固定的字面量”而 PATINDEX 可以找“符合某种模式的内容”。比如 PATINDEX(%[0-9]%, 订单号A1001) 返回6表示从第6个字符开始出现了数字。这在提取混合文本中的数字、字母、中文片段时极其好用。两者选择逻辑很简单匹配规则固定用 CHARINDEX匹配规则带通配需求用 PATINDEX。另一个区别是 PATINDEX 必须包含通配符参数即使你要精确查找 SQL也得写成 PATINDEX(%SQL%, 原字符串)不能像 CHARINDEX 那样直接传字面量。2.3 截取三兄弟LEFT、RIGHT、SUBSTRING 的核心区分LEFT 从左侧截取RIGHT 从右侧截取SUBSTRING 从任意位置截取指定长度。这三兄弟覆盖了95%的截取场景。LEFT 的参数只有两个LEFT(字符串, 长度)。比如 LEFT(SQL Server, 3) 得到 SQL。RIGHT 同理RIGHT(SQL Server, 6) 得到 Server。SUBSTRING 有三个参数SUBSTRING(字符串, 开始位置, 长度)。SUBSTRING(SQL Server, 5, 3) 得到 Ser。实际项目中截取经常和定位函数嵌套使用。比如从固定格式的编号 ABC-2024-001 中提取中间的年份SUBSTRING(编号, CHARINDEX(-, 编号) 1, 4)。这种组合写法在 ETL 清洗、日志解析里出现频率极高。需要注意SUBSTRING 的开始位置如果为0结果会返回空字符串而不是报错。这个“静默失败”容易埋雷。建议在实际使用时先确认定位函数返回的位置大于0再做截取。一个稳妥的写法是在截取前加一层判断避免空结果被当作有效数据继续参与后续逻辑。3. 修改与转换大小写、空格清洗、替换填充3.1 UPPER 与 LOWER不只是换个大小写UPPER 把字符串全部转为大写LOWER 全部转为小写。作用看起来很直白但有一个隐藏场景容易被忽略数据标准化。用户注册时输入的邮箱、用户名如果不统一转成大写或小写再存储后续比对就会出现 Aliceexample.com 和 aliceexample.com 匹配不上的问题。我在某个用户系统的改造中把所有邮箱字段在写入前统一转小写一下子减少了大量重复账号。应用层做大小写转换很简单但如果你在 SQL 里直接对列做 UPPER 处理会导致该列上的普通索引失效。想要既规范化又不牺牲性能建议在写入端做转换查询端直接对比格式化后的值。3.2 LTRIM、RTRIM 与去空格陷阱LTRIM 去除字符串左边的空格RTRIM 去除右边的空格。注意SQL Server 里没有一个默认函数能同时去掉左右两边的空格需要嵌套使用LTRIM(RTRIM(字符串))。习惯写其他编程语言的同事刚接触时经常找 TRIM 函数找不到。更隐蔽的坑在于这些函数默认只处理空格不处理制表符、换行符等不可见字符。如果导入的数据来自 Excel 或文本文件行尾经常带有 CHAR(13) 回车或 CHAR(10) 换行光用 LTRIM/RTRIM 看不到效果。处理这种脏数据需要配合 REPLACE 把回车换行替换掉REPLACE(REPLACE(字符串, CHAR(13), ), CHAR(10), )。这套组合写法在数据清洗中几乎是标配。还有一个容易忽略的点中文字符串中间可能混有全角空格也就是 Unicode 编码为 12288 的字符。LTRIM、RTRIM 对全角空格无效。清洗时要把全角空格一并替换REPLACE(字符串, NCHAR(12288), )。处理导入的外部数据时我会先跑一条查询看看字符串里的字符编码分布确认有没有全角空格混入再决定清洗方案。3.3 REPLACE 与 STUFF替换的两种思路REPLACE 是把指定子串全部替换成新内容适合“把A全部变成B”的场景。比如把手机号中间四位打码REPLACE(手机号, SUBSTRING(手机号, 4, 4), ****)。这在做数据脱敏演示时很常用。STUFF 则是“先删除、再插入”的组合操作。语法是 STUFF(原字符串, 开始位置, 删除长度, 插入字符串)。它先删除从开始位置起指定长度的字符再把新字符串插入删除的位置。STUFF 在需要替换字符串中固定位置的片段时更直观比如把 SQLServer 修改为 SQL Database想在第4个字符后插入空格和 DatabaseSTUFF(SQLServer, 4, 0, Database) 即可删除长度设为0时就是纯插入。两者区别一句话总结REPLACE 关心“内容匹配”STUFF 关心“位置操作”。如果被替换的文本位置固定但内容不定用 STUFF 更合适如果内容规律明显、位置不固定用 REPLACE 更合适。注意 REPLACE 是全局替换会把字符串里所有匹配的子串都换掉如果只想替换第一次出现的需要配合 STUFF CHARINDEX 组合来实现。3.4 ASCII、CHAR、UNICODE 与 NCHAR字符编码的底层操作这四个函数处理的是字符与其编码数值之间的转换。ASCII 返回字符的ASCII码CHAR 是它的逆操作。比如 ASCII(A) 返回65CHAR(65) 返回 A。UNICODE 返回字符的Unicode码值NCHAR 是它的逆操作。这几个函数在普通开发中不常用但在以下三种场景里非常关键生成特殊字符比如回车 CHAR(10)、制表符 CHAR(9)、按编码规则过滤数据、判断字符串是否包含中文字符。判断中文字符可以这样写WHERE UNICODE(SUBSTRING(字段, 1, 1)) 127或使用 PATINDEX(%[一-龥]%) 这类范围匹配。这类底层操作还有个典型用途构造分隔符拼接。比如在生成 CSV 导出文件时需要用 CHAR(44) 表示逗号、CHAR(13)CHAR(10) 表示换行配合字符串拼接函数一步到位。很多人不会注意这些细节直到客户端导出文件格式错乱才返工。4. 模糊匹配利器LIKE 与 PATINDEX 的进阶用法4.1 LIKE 的通配符完整指南LIKE 是 SQL Server 最常用的模糊匹配手段。通配符有五种% 匹配任意长度字符_ 匹配单个字符[abc] 匹配方括号中的任意一个字符[a-z] 匹配指定范围内的任意一个字符[^abc] 匹配不在方括号中的任意一个字符。举几个实际例子。查所有姓“张”的用户WHERE 姓名 LIKE 张%。查手机号第二位是3或5的用户WHERE 手机号 LIKE 1[35]%。查姓名中第二个字不是“小”的用户WHERE 姓名 LIKE _[^小]%。LIKE 匹配有一个必须警惕的性能问题以 % 开头的模式无法使用索引比如 LIKE %关键词% 会扫描全表。但如果模式是“前缀匹配”比如 LIKE 张%在合适的索引和排序规则下是可以走索引的。设计模糊查询时能写成前缀匹配就尽量别用双向百分号。4.2 PATINDEX 实现模式定位PATINDEX 和 LIKE 使用同样的通配符体系但返回的是匹配子串的起始位置而不是简单的真/假。这一点让它适合做“提取”操作。举一个经典案例从地址字符串里提取数字门牌号。地址格式为“XX市XX区XX路123号”要提取123可以写成SELECT PATINDEX(%[0-9]%号, 地址)它会返回第一个数字出现的位置。再用 SUBSTRING 配合长度就能把门牌号整体拖出来。这类需求在物流地址解析、报表数据清洗里非常常见。PATINDEX 的另一个用途是做复杂条件判断判断字符串里是否同时包含数字和字母。比如判断密码强度WHERE PATINDEX(%[0-9]%, 密码) 0 AND PATINDEX(%[A-Za-z]%, 密码) 0。这比在一长串 OR 条件里写多个 LIKE 要清爽得多。4.3 通配符匹配的转义与特殊字符处理一个被问得很多的坑如果业务数据本身就含有 % 或 _想精确查找这些字符该怎么办比如搜索包含“100%”的折扣字段。直接写 LIKE %100%% 是错的因为第二个 % 会被当作通配符。这里可以用 ESCAPE 子句指定转义字符WHERE 折扣说明 LIKE %100#%% ESCAPE #这个写法告诉 SQL Server井号后面的 % 是普通字符。同理查找含下划线的字符串LIKE %#_% ESCAPE #。这是校验数据时容易漏掉的一个细节字符串清洗阶段不处理转义查询结果就会异常。5. 语义级字符串操作拆分与聚合的新思路5.1 STRING_SPLIT 实现字符串拆分SQL Server 2016及更高版本提供了 STRING_SPLIT 内置函数用于把带分隔符的字符串拆成多行。它的用法很简洁SELECT value FROM STRING_SPLIT(apple,banana,orange, ,);结果返回三行。这个函数在解析标签数据、处理多选表单值、拆分日志字段时非常实用。比如某张表中存的是“1,3,5”代表多个选项ID需要联动到选项表查名称可以先拆再关联。STRING_SPLIT 有两个限制要注意一是它要求数据库的兼容级别至少为130老库用不了二是它只能接收单个字符分隔符如果要按“逗号空格”拆分需要先统一分隔符再调用函数。以前我在处理用户导入数据时就踩过这个坑分隔符五花八门最后在调用前把中文逗号统一替换成英文逗号才稳定下来。老版本数据库没有这个函数常见替代方案是使用 XML 或递归 CTE 方式实现同样的拆分效果。但从性能和可维护性角度能升级到新版本就用新函数别为了兼容旧语法绕路。5.2 STRING_AGG 实现分组聚合拼接有拆就有合。STRING_AGG 把同一组的多个字符串拼接成一个带分隔符的字符串功能上相当于“分组版”的拼接。用法SELECT 部门, STRING_AGG(员工姓名, ,) AS 员工列表 FROM 员工表 GROUP BY 部门;这个函数一个关键特性是可以指定排序顺序WITHIN GROUP (ORDER BY 入厂日期)。这在拼接排序敏感的数据比如多个流程节点按时间排列时很关键。若忘记指定拼接顺序不保证结果可能不稳定。STRING_AGG 同样要求数据库兼容级别至少为130。老版本中常用 FOR XML PATH 方案来实现拼接但那段写法可读性差、逻辑绕能换就换。拼接过程还有一个需要注意的点如果希望去掉 NULL 值STRING_AGG 会自动忽略 NULL但如果你拼接的是空字符串它不会自动过滤结果里可能出现连续分隔符需要在拼接前用 NULLIF 做处理。5.3 CONCAT 与 CONCAT_WS推荐优先使用的拼接方式CONCAT 函数接受至少两个参数自动把各参数转成字符串并拼接。最大好处是它把 NULL 自动视为空字符串不会让整个拼接结果变成 NULL。这一点和传统的“”运算符完全不同。“”拼接时一旦某个值为 NULL整个结果就是 NULL常常导致数据丢失。CONCAT_WS 则更进一步它指定分隔符并且自动忽略 NULL 值。比如 CONCAT_WS(,, a, NULL, b) 返回 a,b。这在拼接用户姓名、地址组件时非常方便不用一个个判断是否为 NULL。我在生成报表列名和导出 CSV 时都优先用 CONCAT_WS少写了不少判断逻辑。5.4 FORMAT 与转换类的现代化选项FORMAT 函数按指定格式字符串来格式化值。它可以排版日期和数字比如 FORMAT(日期列, yyyy年MM月dd日) 或 FORMAT(金额, N2)。这个函数原理解读起来很简单但它依赖 .NET 的格式字符串机制灵活性极高代价是性能相对差。在大量数据上循环调用 FORMAT查询速度会明显变慢。如果只是简单日期格式化建议优先考虑 CONVERT 的样式参数性能更好。生成业务编号时FORMAT 还常配合字符串补齐需求。比如把数字1转成 0001。更常见的做法是 RIGHT(000 数字串, 4)这比 FORMAT 轻量得多。处理海量数据时性能差距很值得注意。6. 性能陷阱与最佳实践6.1 函数作用在列上索引失效的头号原因这是性能问题中最常见的一条。查询条件是 WHERE SUBSTRING(姓名, 1, 1) 张虽然逻辑正确但 SQL Server 必须对每一行的姓名列执行 SUBSTRING 操作之后才能比较因此无法使用姓名列上的索引。正确做法是改写成范围查询WHERE 姓名 LIKE 张%。LIKE 前缀匹配可以利用索引值越大效果越明显。同理WHERE UPPER(邮箱) ALICEEXAMPLE.COM 也不利于索引使用。如果业务需要不区分大小写地比对应确保列排序规则本身不区分大小写或者预先在应用层统一大小写存储而不是查询时再去转换。6.2 LIKE %关键词% 为什么慢模糊搜索是慢查询重灾区。WHERE 备注 LIKE %重要% 这种写法会让 SQL Server 扫描整张表每行都做匹配。当表只有几百行时感觉不到一旦数据量到百万级响应时间会迅速恶化。两种常见优化手段一种是把双向百分号查询改造成纯前缀查询例如 LIKE 重要%尝试走索引范围扫描另一种是引入全文索引或第三方搜索引擎把关键词匹配交给更擅长这项工作的组件。具体选哪种取决于业务对实时性和结果准确性的要求。纯粹把 LIKE %...% 保留在核心业务链路上是我最不建议的做法。6.3 隐式转换与排序规则冲突字符串函数和数据类型组合在一起时还容易出现隐式转换问题。例如 varchar 列和 nvarchar 参数比较时SQL Server 可能把整列转为 nvarchar 再比较导致索引失效。这个问题的征兆是执行计划中出现 CONVERT_IMPLICIT 警告。发现这种警告时优先调整参数类型与列类型一致比单纯改函数更有效。排序规则冲突是另一个经典问题。两列分别来自不同数据库或不同排序规则时直接做等值连接会报错。解决方式是使用 COLLATE 子句显式统一排序规则比如 ON a.姓名 b.姓名 COLLATE Chinese_PRC_CI_AS。这种冲突在字符串连接、关联查询、聚合分组中都可能出现排查时看报错信息里的 Collation 关键词能快速定位。6.4 字符串拼接与 NULL 的纠缠“”拼接时 NULL 会导致整个结果变成 NULL这是开发中比较隐蔽的数据丢失源头。例如某个客户地址由省、市、区三个字段拼接中间某一段缺失最终地址栏会整个消失而不是显示缺少一部分。这个问题用 CONCAT 或 CONCAT_WS 可以直接规避因为它们对 NULL 的处理逻辑更友好。如果使用的 SQL Server 版本较老没有 CONCAT_WS可以用 ISNULL 或 NULLIF 搭配处理CONCAT(ISNULL(省, ), ISNULL(市, ))。动手前先确认自己的目标版本支持哪些函数避免写完才发现语法不支持。6.5 拼接列值的语义陷阱聚合拼接时容易犯一个错误没有考虑 NULL 分隔位置。比如姓、名分开存储希望拼成全名时用“姓名”最简单但如果中间需要加“·”之类的连接符就要小心 NULL 值。常见错误写法是直接 姓 · 名一旦名为 NULL整个结果为 NULL还不如不拼接。用 CONCAT_WS(·, 姓, 名) 可以优雅地跳过 NULL结果更可控。7. 实战案例一个完整的字符串处理场景7.1 场景描述与需求分解假设某个项目中有一张客户表其中地址字段存的是“省市区详细地址”混杂文本例如“广东省深圳市南山区科技园路100号”。现在报表需要展示省、市、区三个独立列。数据格式相对固定但长度不固定而且可能有些记录缺少区级信息。目标是用字符串函数把地址拆干净且不因缺失报错。需求拆成两个子任务按位置规律截取省市区三个部分对缺失内容做兼容处理。7.2 SQL实现与关键点讲解省的部分最简单取前3位LEFT(地址, 3)。市的部分从第4位开始到“市”字结束SUBSTRING(地址, 4, CHARINDEX(市, 地址) - 3)。区的部分要找到“市”的位置再从其后一位开始截到“区”或“县”结束SUBSTRING(地址, CHARINDEX(市, 地址) 1, CHARINDEX(区, 地址) - CHARINDEX(市, 地址))。这里有个细节如果区级缺失CHARINDEX(区, 地址) 会返回0截取长度为负值结果直接报错。稳妥的写法是先用 CASE 判断区结尾是否存在不存在就返回 NULL 或空字符串。实际生产环境里脏数据远比干净数据多这种防御性写法非常有必要。按这个思路组合出的查询足以支撑报表口径。如果是数据量大的清洗任务我会先把处理逻辑写成函数或存储过程批量执行而不是每条记录重复解析这样既能复用又利于追踪验证逻辑变更。7.3 导出场景用字符串函数生成结构化文本另一个实用场景是生成 CSV 文件。许多旧系统没有专门导出组件直接从 SQL Server 查询结果生成文本时需要手动把多列拼成一行。正确的做法是使用 CONCAT_WS 或 CONCAT 加分隔符避免 NULL 导致整行丢失。若客户要求导出文件在 Excel 中打开不变形可以预先处理逗号、换行符等特殊字符。实际导出时最怕的是数据本身包含逗号或换行这会导致 CSV 列错位。解决思路是把字段中可能出现的逗号替换为中文逗号把换行替换为空格再拼接。虽然不能保证100%还原但在业务报表场景下已经足够干净。这类清洗逻辑在 SQL 里用 REPLACE 单层处理即可。8. 常见问题与排查思路速查8.1 函数返回值的边界情况整理了一份速查表覆盖了字符串函数最常见的边界情况场景示例结果原因查找不存在的中文子串CHARINDEX(xx, SQL Server)0未找到返回0SUBSTRING 开始位置为0SUBSTRING(abc, 0, 2)空字符串开始位置小于1时返回空SUBSTRING 超长截取SUBSTRING(abc, 2, 10)bc超出部分自动忽略LEN 不计尾随空格LEN(abc )3内置行为中文全角空格清洗LTRIM( abc) abc默认只处理半角空格字符串末尾换行残留RTRIM(abc\r\n)abc\r\nRTRIM 不处理控制字符这张表的最后一列“原因”是理解问题的钥匙。每次排查字符串函数相关异常我都会先对照这类边界行为判断问题出在函数本身还是数据本身。8.2 报错信息与解决方案实际开发中经常遇到几种报错信息这里给出常见原因和解决方向。“传递给 LEFT 或 SUBSTRING 函数的长度参数无效”通常是截取长度为负数原因是 CHARINDEX 返回0。解决方案是先验证目标分隔符是否存在再做截取。“无法解决排序规则冲突”多表关联时两列排序规则不一致。解决方案是在关联条件或计算表达式中使用 COLLATE 显式指定排序规则。“STRING_SPLIT 不可用”数据库兼容级别低于130。解决方式是升级兼容级别或者切换到 FOR XML PATH 方案。注意兼容级别变更会影响其他行为上线前务必充分测试。“TRIM 不是可识别的内置函数名称”版本较老不支持 TRIM。低版本中需要回到 LTRIM RTRIM 嵌套。这也是我建议先确认目标版本再决定写法的原因。8.3 排查字符串问题的通用思路一套我调试了很多次后总结出的排查思路分享在这里。先看数据再看函数。很多问题其实不是函数写错而是数据里有看不见的特殊字符。先用 DATALENGTH 与 LEN 对比如果两者差异比预期大说明存在尾随空格或非普通字符。再用 UNICODE 和 ASCII 对可疑字符做编码检查。再看函数参数重点确认位置计数起点。SQL Server 的位置计数从1开始这一点和许多编程语言不同。CHARINDEX、PATINDEX、SUBSTRING 三者的位置参数要保持一致。最后看执行计划。如果字符串处理函数出现在 WHERE 子句且作用在列上留意是否引起全表扫描。发现索引失效时优先优化写法而不是在索引上叠加更多函数。9. 个人经验写字符串处理代码时的几条习惯字符串函数这一章其实最难的从来不是背函数而是建立“先想清楚数据的真实情况再选择函数组合”的习惯。我踩过很多坑之后逐渐养成了几条固定做法写在这里供你参考。第一写任何字符串拼接前先想清楚 NULL 会怎么影响结果。能写 CONCAT 就不写“”能写 CONCAT_WS 就尽量用。哪怕当前数据看起来很干净也保不齐哪天上游就补录了一条空记录。第二定位查找结果一定要做存在性判断。CHARINDEX 返回0的情况太常见如果直接拿它去算 SUBSTRING 的起始位置很容易踩到长度参数为负的报错。宁可多写一层 CASE也不要拿线上事故换教训。第三排查乱码和长度异常时先检查是不是全角空格和回车换行在捣乱。这两个隐形字符在导入类业务中极其常见普通函数查不出问题只有在编码层面才能看到端倪。第四新版函数能用的就用新版。STRING_SPLIT 和 STRING_AGG 出现后大大简化了拆分和聚合拼接的写法。只要兼容级别允许就别再用老一套 XML 拼接方案维护成本根本不是一个量级。这章内容到这儿已经把所有常用字符串函数和主要踩坑点都过了一遍。最后再分享一个我个人的小习惯写复杂字符串表达式之前先在一个临时查询窗口里用 SELECT 直接跑一遍各个中间结果确认每段截取、每次替换都符合预期再嵌套进正式查询。这套方法帮我挡下了许多看起来“莫名其妙”的脏数据问题希望你也能用上。