【问题标题】:How to split a comma delimited column into rows along with a non-unique ID column through SQL如何通过 SQL 将逗号分隔的列与非唯一 ID 列拆分为行
【发布时间】:2019-08-15 00:52:45
【问题描述】:

我想要一些关于如何完成这项任务的建议。如何创建 sql 语句以将表转换为显示的预期输出?只是希望指出正确的方向!

是否可以仅使用读取权限来执行此操作?因此无法创建函数或额外的表。我有 SQL Server 2012,但可以升级到 2016。

编辑:对于之前 ID 列的错误示例,我真的很抱歉。 ID 列现在是唯一的主键。感谢您的所有建议和帮助。

Table:
ID      Value
100     aaa, bbb, ccc
101     aaa, bbb, ccc
102     aaa, bbb, ccc
103     abc, bcb, zzz
104     abc, bcb, zzz
105     abc, bcb, zzz


Expected:
ID      Value
100     aaa
101     bbb
102     ccc
103     abc
104     bcb
105     zzz

【问题讨论】:

  • 您确定您的表格数据正确吗?似乎每个 id 值只有一行,然后您希望将 value 列解析为单独的行。
  • 解析成三列是可行的。只需搜索带有对charindex() 的嵌套调用的逗号即可。使用cross applyvalues 获取多行。
  • T-SQL split string的可能重复

标签: sql tsql split sql-server-2012


【解决方案1】:

为此,您将需要 Jeff Moden 的 Dilimited 8K Split 功能,您可以找到 here。安装该功能后(在 SPLIT_STRING 出现时,您将多次使用该功能,直到 SQL Server 2016 出现),您可以使用以下代码解决您的问题:

DECLARE @t TABLE
(
Id INTEGER,
Val VARCHAR(20)
);

INSERT INTO @t VALUES
(1,'aaa,bbb,ccc'),
(1,'aaa,bbb,ccc'),
(1,'aaa,bbb,ccc'),
(2,'abc,bcb,zzz'),
(2,'abc,bcb,zzz'),
(2,'abc,bcb,zzz');

SELECT DISTINCT t.Id, item, ItemNumber
FROM @t t
CROSS APPLY [dbo].[DelimitedSplit8K](t.Val, ',');

--results
Id          item     RowNumber
----------- -------- --------------------
1           aaa      1
1           bbb      2
1           ccc      3
2           abc      1
2           bcb      2
2           zzz      3

【讨论】:

  • 内置 string-_split 是在 2016 年推出的,而不是 2017 版。此外,在 2016 版本之前还有其他拆分字符串的方法。阅读 Aaron Bertrand 的 Split strings the right way – or the next best way 了解详情。
  • 还有一件事——你使用了错误的order byrow_number()——你应该在order by子句中使用ItemNumber(从Moden的函数返回的第二列),否则你' 将得到一个可能正确也可能不正确的任意 row_number。
  • 我已经编辑了我的答案以显示正确的版本 SPLIT_STRING 出来了。在 id 前面,它在给定输入的情况下产生正确的结果。 id 与我编写的查询相同。在这里使用 ItemNumber 从字面上看没有任何区别,您的评论只会让事情变得更加混乱。
  • PARTITION BY Id ORDER BY id 表示您正在按常数值排序 - 这与根本没有排序一样任意。您可能会在测试中获得当前结果,但无法保证它是一致的 - 这意味着您每次运行查询时都有可能出现顺序错误。
  • 对不起,英语不是我的母语,我不熟悉“come away as a burk”这个短语。无论如何,很高兴我们能达成一致。
【解决方案2】:

为了改进 Jim 上面的回答,我建议我们在可能的情况下使用删除重复项 执行拆分之前。这将导致要过滤的重复项数量少得多。使用此示例数据...

CREATE TABLE #t
(
  Id  INT,
  Val VARCHAR(20)
);

INSERT INTO #t VALUES
(1,'aaa,bbb,ccc'),
(1,'aaa,bbb,ccc'),
(1,'aaa,bbb,ccc'),
(2,'abc,bcb,zzz'),
(2,'abc,bcb,zzz'),
(2,'abc,bcb,zzz');

...我们可以比较执行计划以了解我的意思。打开“包括实际执行计划”运行:

-- Remove Duplicates BEFORE the split
SELECT t.Id, s.ItemNumber, s.item
FROM (SELECT DISTINCT t.* FROM #t AS t) AS t
CROSS APPLY [dbo].[DelimitedSplit8K](t.Val, ',') AS s;

-- Remove Duplicates AFTER the split
SELECT DISTINCT t.Id, s.ItemNumber, s.item
FROM #t AS t
CROSS APPLY [dbo].[DelimitedSplit8K](t.Val, ',') AS s; 

下面是执行计划。使用此示例数据,在拆分之前删除重复项会导致内部循环连接和合并连接运算符中有 6 行,并且只有 2 行得到排序。拆分后删除重复项会导致 Loop 和 Merge 连接运算符中的 18 行和 6 行得到排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2019-11-10
    • 2018-11-02
    相关资源
    最近更新 更多