如何在 SQL Server 中高效实现字符串分拆语句?

来源:站长站作者:小师妹头衔:草根站长
导读:本期聚焦于小伙伴创作的《如何在 SQL Server 中高效实现字符串分拆语句?》,敬请观看详情。把逗号隔开的字符串拆成多行,是写报表和存储过程时经常碰到的需求。早期版本只能靠自定义函数循环截取,不仅代码冗长,遇到万级数据还会明显变慢。SQL Server 2016 之后内置的 STRING_SPLIT 函数用纯 C++ 实现,直接返回表值结果,执行计划更优。不过它不保证输出顺序,且低版本无法使用。另一种常见做法是借助 XML 或临时表,虽然兼容性好,但写法繁琐且容易因特殊字符报错。理解各方案底层机制和适用场景,才能在实际业务里选出最稳的实现方式。

在 SQL Server 的实际业务处理中,经常需要将一个由逗号、竖线或其他分隔符拼接而成的长字符串,拆分成多行单独的值,以便关联查询或批量写入。这种操作通常被称为字符串分拆。不同版本的 SQL Server 提供的原生能力差异很大,选择合适的方法直接影响脚本的可读性和执行效率。

如何在 SQL Server 中高效实现字符串分拆语句?

一、使用内置 STRING_SPLIT 函数

从 SQL Server 2016(兼容级别 130)开始,系统提供了原生的 STRING_SPLIT 函数。它接收两个参数:待拆分的字符串和分隔符,返回一个只有一列叫 value 的表。由于该函数由数据库引擎底层用 C++ 实现,避免了用户自定义函数中的逐行解释执行开销,在绝大多数场景下性能最佳。

下面的示例演示如何将一个商品编号列表拆开,并与商品表做关联查询:

DECLARE @ids NVARCHAR(200) = '1001,1002,1003,1004';
SELECT p.id, p.name
FROM product p
INNER JOIN STRING_SPLIT(@ids, ',') AS s
  ON p.id = CAST(s.value AS INT);

需要注意的是,STRING_SPLIT 的官方文档明确说明:输出行的顺序是不保证的。如果你的业务逻辑强依赖原始字符串中的先后顺序,就不能直接使用它,或者需要配合其它方式标记序号。此外,分隔符仅支持单个字符,不支持多字符分隔串。

对于低于 2016 的实例,这个函数不存在,执行会报无效的对象名错误。此时必须采用兼容旧版本的自定义方案,后文会给出典型写法。

二、自定义表值函数实现分拆

在老版本或需要保持顺序、支持多字符分隔符时,开发者通常编写自定义表值函数(TVF)。最常见的是利用数字辅助表或递归方式循环截取。下面给出一个基于数字表的通用拆分函数示例:

CREATE FUNCTION dbo.fn_SplitWithSeq
(
  @str NVARCHAR(MAX),
  @sep NVARCHAR(10)
)
RETURNS @t TABLE (seq INT, val NVARCHAR(MAX))
AS
BEGIN
  DECLARE @i INT = 1, @pos INT, @len INT = LEN(@sep);
  SET @str = @str + @sep;
  WHILE CHARINDEX(@sep, @str, @i) > 0
  BEGIN
    SET @pos = CHARINDEX(@sep, @str, @i);
    INSERT INTO @t(seq, val)
      VALUES (NULL, SUBSTRING(@str, @i, @pos - @i));
    SET @i = @pos + @len;
  END
  UPDATE @t SET seq = ROW_NUMBER() OVER (ORDER BY (SELECT 1));
  RETURN;
END;

这个函数通过 CHARINDEX 不断查找分隔符位置,用 SUBSTRING 截取片段,并借助临时表变量缓存结果。最后用窗口函数补齐序号,从而保留了原始顺序。它的优势在于逻辑透明、可扩展,但缺点也明显:循环处理在超长字符串时会产生大量语句执行,速度远不及内置函数。

如果系统里经常调用此类函数,建议预先建一张物理数字表(如 dbo.Nums 存有 1 到 100000 的整数),改用基于集合的写法代替 WHILE 循环,能显著提升性能。

三、借助 XML 方法进行分拆

另一种在不支持 STRING_SPLIT 的环境里流行的技巧,是把字符串伪装成 XML 再使用 nodes() 方法拆开。该方法纯集合操作,无需循环,兼容性可到 SQL Server 2005。

DECLARE @xml XML;
DECLARE @str NVARCHAR(MAX) = '苹果,香蕉,橘子';
SET @xml = CAST('<r>' + REPLACE(@str, ',', '</r><r>') + '</r>' AS XML);
SELECT t.c.value('.', 'NVARCHAR(50)') AS fruit
FROM @xml.nodes('/r') AS t(c);

上面的代码先将逗号替换成 XML 标签,再强制转换成 XML 类型,最后用 nodes 把每个标签变成一行。这种做法代码紧凑,且能自然处理特殊字符(只要做好转义)。不过当原始字符串里本身包含尖括号或 & 符号时,必须先进行转义替换,否则 CAST 会报错。

从执行计划看,XML 方式会引入 XML 解析器开销,在数据量很大时不如数字表集合解法,但远好于逐行自定义函数。它适合偶尔使用的脚本或中小数据量的报表存储过程。

四、不同方案对比与选型建议

为了直观比较,我们把三种主流做法放在一张表里看差异:

方案最低版本是否保序性能表现适用场景
STRING_SPLIT2016最优高并发、大批量、无顺序要求
自定义TVF2005+可保序较差旧版本、需序号、低频调用
XML解析2005+保序中等中小数据、报表脚本

在新建项目且数据库版本允许时,优先使用 STRING_SPLIT,并用 OPENJSON 等补充手段解决顺序问题。维护老系统时,推荐用数字表配合基于集合的自定义函数替换 WHILE 循环实现,既保证兼容也兼顾效率。避免在触发器或高频作业中调用逐行截取的函数,那会成为整个库的瓶颈。

字符串分拆虽是小功能,却集中体现了 SQL Server 集合思维与过程思维的差异。理解每种写法的内部机制,才能在正确的地方用正确的语句。

SQL_Server字符串分拆STRING_SPLIT修改时间:2026-08-05 05:48:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。