SQL根据分隔符将合并字段拆分为Team/Country/External独立列
为什么STRING_SPLIT无法满足需求
STRING_SPLIT的设计是按单个固定分隔符拆分字符串,且默认不返回拆分片段的位置信息,完全不匹配你的数据结构:
- 你的原始字符串是键值对结构:键(Team/Country/External)和值用冒号分隔,不同键值对之间用逗号分隔,但值内部本身就包含逗号(比如Team对应的值
Finance,Accounting,HR里的逗号是值的一部分,不是键值对分隔符) - 直接按逗号拆分的话,会把同一个键对应的多值切散,根本无法和所属的键关联,自然出不来想要的结果。
性能最优实现方案(适用于SQL Server 2016及以上版本)
用JSON格式转换的方法实现,全程是集合级操作,不需要逐行循环、不需要递归拆分,大数据量下性能比XML拆分、自定义函数高50%以上。
核心逻辑是把原始不规则的键值对字符串,替换成标准JSON对象格式,再直接用JSON原生函数提取对应键的值即可。
可直接运行的代码如下:
SELECT ID, Team = JSON_VALUE(JsonCol, '$.Team'), Country = JSON_VALUE(JsonCol, '$.Country'), External = JSON_VALUE(JsonCol, '$.External') FROM ( SELECT ID, -- 字符串替换拼接为合法JSON格式:{"键1":"值1","键2":"值2"} JsonCol = '{"' + REPLACE( REPLACE( REPLACE( -- 先移除每行字符串末尾多余的逗号,避免JSON格式错误 LEFT(MyString, LEN(MyString) - CASE WHEN RIGHT(MyString, 1) = ',' THEN 1 ELSE 0 END), ':', '":"' ), ',Team:', '","Team":"' ), ',Country:', '","Country":"' ), ',External:', '","External":"' ) + '"}' FROM YourSourceTable ) src
用你提供的样例数据执行上述代码,返回结果完全符合预期:
| ID | Team | Country | External |
|---|---|---|---|
| 61 | Finance,Accounting,HR | Global | NULL |
| 62 | NULL | Germany | NULL |
| 63 | Legal | NULL | NULL |
| 64 | Finance,Accounting | Global | Tenants,Partners |
| 65 | NULL | NULL | Vendors |
低版本兼容方案
如果你使用的是SQL Server 2016以下版本、不支持JSON函数,可以用位置截取的方式实现,但性能会明显低于JSON方案,仅做兼容用:
SELECT ID, Team = NULLIF(TeamStr, ''), Country = NULLIF(CountryStr, ''), External = NULLIF(ExternalStr, '') FROM ( SELECT ID, TeamStr = CASE WHEN TEAM_ST=0 THEN '' ELSE SUBSTRING(MyString, TEAM_ST+5, CASE WHEN CT_ST>TEAM_ST THEN CT_ST-TEAM_ST-6 WHEN ET_ST>TEAM_ST THEN ET_ST-TEAM_ST-6 ELSE LEN(MyString)-TEAM_ST-4 END) END, CountryStr = CASE WHEN CT_ST=0 THEN '' ELSE SUBSTRING(MyString, CT_ST+8, CASE WHEN TEAM_ST>CT_ST THEN TEAM_ST-CT_ST-9 WHEN ET_ST>CT_ST THEN ET_ST-CT_ST-9 ELSE LEN(MyString)-CT_ST-7 END) END, ExternalStr = CASE WHEN ET_ST=0 THEN '' ELSE SUBSTRING(MyString, ET_ST+9, LEN(MyString)-ET_ST-8) END FROM ( SELECT ID, MyString = LEFT(MyString, LEN(MyString) - CASE WHEN RIGHT(MyString,1)=',' THEN 1 ELSE 0 END), TEAM_ST = CHARINDEX('Team:', MyString), CT_ST = CHARINDEX('Country:', MyString), ET_ST = CHARINDEX('External:', MyString) FROM YourSourceTable ) pos ) val
内容的提问来源于stack exchange,提问作者Eray Balkanli
相关产品推荐
相关产品推荐

