You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:SQL实现多分隔符字符串拆分多行多列的动态查询(无函数)

动态拆分字符串为姓名-年龄对应行的SQL实现

我来帮你搞定这个字符串拆分的问题!你想要把类似'John, Mark, Peter|23, 32, 45'这样的字符串拆分成姓名和年龄一一对应的行,还要动态处理任意数量的记录,而且尽量不用自定义函数对吧?之前试Cross Apply没成功,大概率是没处理好两部分拆分后的顺序关联,我给你两个可行的方案,分别适配不同的SQL Server版本:

方案一:适用于SQL Server 2022及以上版本(推荐)

SQL Server 2022开始,STRING_SPLIT函数新增了ordinal参数,能保证拆分后的结果和原字符串中的顺序完全一致,这就完美解决了姓名和年龄的对应问题。我们可以先把主字符串按|拆分成姓名列表和年龄列表,再分别拆分这两个列表,最后通过序号关联:

DECLARE @input NVARCHAR(MAX) = 'John, Mark, Peter|23, 32, 45';

WITH main_parts AS (
    -- 拆分主字符串为姓名串和年龄串
    SELECT 
        MAX(CASE WHEN ordinal = 1 THEN value END) AS name_str,
        MAX(CASE WHEN ordinal = 2 THEN value END) AS age_str
    FROM STRING_SPLIT(@input, '|', 1) -- 第三个参数1启用ordinal返回
)
SELECT 
    TRIM(n.value) AS Name, -- TRIM去掉每个值前后的空格
    TRIM(a.value) AS Age
FROM main_parts
-- 拆分姓名串为单个姓名,保留序号
CROSS APPLY STRING_SPLIT(name_str, ',', 1) n
-- 拆分年龄串为单个年龄,保留序号
CROSS APPLY STRING_SPLIT(age_str, ',', 1) a
-- 通过序号匹配姓名和年龄
WHERE n.ordinal = a.ordinal;

执行后会得到:

NameAge
John23
Mark32
Peter45

方案二:适用于SQL Server 2017及以下版本

如果你的SQL Server版本不支持带ordinal的STRING_SPLIT,可以用XML拆分法配合行号来保证顺序,同样不需要自定义函数:

DECLARE @input NVARCHAR(MAX) = 'John, Mark, Peter|23, 32, 45';

WITH main_parts AS (
    -- 先拆分主字符串为姓名串和年龄串
    SELECT 
        LEFT(@input, CHARINDEX('|', @input) - 1) AS name_str,
        RIGHT(@input, LEN(@input) - CHARINDEX('|', @input)) AS age_str
),
name_split AS (
    -- 拆分姓名串,生成带行号的姓名列表
    SELECT 
        TRIM(Split.a.value('.', 'NVARCHAR(100)')) AS Name,
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ordinal
    FROM (
        SELECT CAST('<item>' + REPLACE(name_str, ',', '</item><item>') + '</item>' AS XML) AS Data
        FROM main_parts
    ) AS A
    CROSS APPLY Data.nodes('/item') AS Split(a)
),
age_split AS (
    -- 拆分年龄串,生成带行号的年龄列表
    SELECT 
        TRIM(Split.a.value('.', 'NVARCHAR(100)')) AS Age,
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ordinal
    FROM (
        SELECT CAST('<item>' + REPLACE(age_str, ',', '</item><item>') + '</item>' AS XML) AS Data
        FROM main_parts
    ) AS A
    CROSS APPLY Data.nodes('/item') AS Split(a)
)
-- 通过行号关联姓名和年龄
SELECT ns.Name, aspl.Age
FROM name_split ns
JOIN age_split aspl ON ns.ordinal = aspl.ordinal;

这个方案的核心是用XML把逗号分隔的字符串转成节点集合,再通过ROW_NUMBER()生成顺序号,确保姓名和年龄的位置一一对应。

为什么你之前的Cross Apply没成功?

大概率是没处理好拆分后的顺序问题——如果拆分姓名和年龄时没有保留原顺序,直接关联就会出现匹配错误。上面的两个方案都重点保证了顺序的一致性,这是解决问题的关键。

内容的提问来源于stack exchange,提问作者Flavio Justino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:03:38