将相关的逗号分隔字符串转换为具有多列的单个行

时间:2017-08-24 12:47:13

标签: sql-server sql-server-2016

以前有人问过Turning a Comma Separated string into individual rows。这适用于一列,但我有一个扩展问题。如果我想拆分两个(或更多)相关列,该怎么办?也就是说,如果我有这样的数据(使用前一篇文章中的数据作为基础):

| SomeID         | OtherID     | Data      | RelatedData |
+----------------+-------------+-----------+-------------+
| abcdef-.....   | cdef123-... | 18,20,22  | xxx,,yyy    |
| abcdef-.....   | 4554a24-... | 17,19     | a,bb        |
| 987654-.....   | 12324a2-... | 13,19,20  | r,s,t       |

并希望返回如下行:

| SomeID         | OtherID     | Data | RelatedData |
+----------------+-------------+------+-------------+
| abcdef-.....   | cdef123-... | 18   | xxx         |
| abcdef-.....   | cdef123-... | 20   |             |
| abcdef-.....   | cdef123-... | 22   | yyy         |
| abcdef-.....   | 4554a24-... | 17   | a           |
| abcdef-.....   | 4554a24-... | 19   | bb          |
| ...            | ...         | ...  | ...         |

由于其简单性,我希望使用STRING_SPLIT,但我找不到让它工作的方法。这不起作用:

select OtherID, cs1.Value, cs2.Value
from yourtable
cross apply STRING_SPLIT (Data, ',') cs1
cross apply STRING_SPLIT (RelatedData, ',') cs2

有什么建议吗?

1 个答案:

答案 0 :(得分:4)

我同意有关此设计的评论。最好将数据标准化。

要使用string_split()执行此操作,您可以将row_number()解决方法用于序数,如下所示:

;with cs1 as (
  select SomeId, OtherId, x.Value
    , ItemNumber = row_number() over (partition by t.SomeId, t.OtherId order by (Select Null))
  from t
    cross apply string_split(Data,',') x
)
, cs2 as (
  select SomeId, OtherId, x.Value
    , ItemNumber = row_number() over (partition by t.SomeId, t.OtherId order by (Select Null))
  from t
    cross apply string_split(RelatedData,',') x
)
select cs1.SomeId, cs1.OtherId, cs1.Value, cs2.Value
from cs1 
  inner join cs2
    on cs1.SomeId = cs2.SomeId
   and cs1.OtherId = cs2.OtherId
   and cs1.ItemNumber = cs2.ItemNumber

dbfiddle.uk demo

返回:

+--------------+-------------+-------+-------+
|    SomeId    |   OtherId   | Value | Value |
+--------------+-------------+-------+-------+
| 987654-..... | 12324a2-... |    13 | r     |
| 987654-..... | 12324a2-... |    19 | s     |
| 987654-..... | 12324a2-... |    20 | t     |
| abcdef-..... | 4554a24-... |    17 | a     |
| abcdef-..... | 4554a24-... |    19 | bb    |
| abcdef-..... | cdef123-... |    18 | xxx   |
| abcdef-..... | cdef123-... |    20 |       |
| abcdef-..... | cdef123-... |    22 | yyy   |
+--------------+-------------+-------+-------+

我认为使用包含序数的自定义函数更简单。例如,Jeff Moden的分隔内联表值函数:

select SomeId, OtherId, cs1.Item, cs2.Item
from t
  cross apply dbo.delimitedsplit8K(Data,',') cs1
  cross apply dbo.delimitedsplit8K(RelatedData,',') cs2
where cs1.ItemNumber = cs2.ItemNumber

返回相同的结果。

拆分字符串参考: