【问题标题】:Split comma separated values of two column by mapping them into new row using SQL通过使用 SQL 将它们映射到新行来拆分两列的逗号分隔值
【发布时间】:2017-04-18 20:50:38
【问题描述】:
ID        NAME          COMMENTS
1          ABC           HI
2,3        DEF,GHI       HELLO
4          JKL           HII
5,6,7      M,N,O         HEY

我的表中的上述数据带有逗号分隔值,这些逗号分隔值是按顺序映射的。 例如。 id 1 与 ABC 相关,2 与 DEF 相关,3 映射到 GHI 等等。

我想使用 sql 查询得到以下输出:

ID        NAME      COMMENTS
1          ABC        HI
2          DEF        HELLO
3          GHI        HELLO
4          JKL        HII
5          M          HEY
6          N          HEY
7          O          HEY

【问题讨论】:

  • mysql 和 SQL server 不一样——是什么?
  • @JenR ... SQL Server
  • 您可以使用任意数量的“SplitString()”表值函数来执行此操作……这是很常见的事情。您只需使用该函数调用 CROSS APPLY,瞧。这可以说是一个重复的问题。
  • @pmbAustin 我知道 CROSS APPLY 的应用,我们在一列中有逗号分隔的值,这里我在多列中有值。如果您有与此问题相关的任何链接,请告诉我
  • 那是@pmbAustin

标签: sql-server tsql


【解决方案1】:

在 SQL Server 2016+ 中,您可以使用 string_split()

在 SQL Server 2016 之前,您需要一些其他方式来拆分字符串。使用 Jeff Moden 的 CSV Splitter 表值函数:

select 
    id = i.item
  , name = n.item
  , comments = t.comments
from t
  cross apply dbo.delimitedsplit8k(t.id,',') i
  cross apply dbo.delimitedsplit8k(t.name,',') n
where i.itemnumber = n.itemnumber

rextester 演示http://rextester.com/EEFRS3810

返回:

+----+------+----------+
| id | name | comments |
+----+------+----------+
|  1 | ABC  | HI       |
|  2 | DEF  | HELLO    |
|  3 | GHI  | HELLO    |
|  4 | JKL  | HII      |
|  5 | M    | HEY      |
|  6 | N    | HEY      |
|  7 | O    | HEY      |
+----+------+----------+

拆分字符串参考:


使用 John Cappelletti 的内联 xml 字符串拆分器:

select 
    id = i.RetVal
  , name = n.RetVal
  , comments = t.comments
from t
   Cross Apply (
                Select RetSeq = Row_Number() over (Order By (Select null))
                      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                From  (Select x = Cast('<x>' + replace((Select replace(t.[Id],',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as x
                Cross Apply x.nodes('x') AS B(i)
             ) i
   Cross Apply (
                Select RetSeq = Row_Number() over (Order By (Select null))
                      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                From  (Select x = Cast('<x>' + replace((Select replace(t.[Name],',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as x
                Cross Apply x.nodes('x') AS B(i)
             ) n
where i.RetSeq = n.RetSeq

rextester 演示:http://rextester.com/ZCKVNV72753

【讨论】:

  • 我最喜欢 Jeff Moden 的拆分器的一点是它是唯一一个包含位置编号的拆分器。这是分离器的重要组成部分,他们中的大多数人都错过了这个简单的添加。即使是新的 string_split 也不包括这个值。不太清楚为什么会这样。
  • @SeanLange 非常好。 iirc John Cappelletti 在他的内联 xml 和 itvf 字符串拆分器函数中都包含一个位置编号(较少发布,但它就在那里)。我还敢打赌他迟早会来,并将其作为在线替代品发布在这里^.^
  • @SeanLange 能否提供不使用任何函数和 SP 的直接 sql 查询。
  • @JohnCappelletti 只是因为我可以使用与拼写密西西比时相同的节奏!
  • @JohnCappelletti,我想哪个翻了一番?然后我记得哦,只是所有的! :-D
【解决方案2】:

如果您有 4 个或更少的分隔项,您可以使用 parsename 拆分它们。对于 4 件或更少的物品,这是可用的最快方法:

示例数据和解决方案

-- Sample data
DECLARE @yourTable TABLE
(
  ID       varchar(100),
  Name     varchar(100),
  Comments varchar(100)
);

INSERT @yourTable VALUES 
  ('1','ABC','HI'),('2,3','DEF,GHI','HELLO'),('4','JKL','HII'),('5,6,7','M,N,O','HEY');

-- solution using parsename for splitting
SELECT 
  ID   = id_new,
  Name = name_new,
  Comments
FROM @yourTable
CROSS JOIN (VALUES (1),(2),(3),(4)) t(N)
CROSS APPLY 
(VALUES 
  (parsename(REPLACE(ID,',','.'), t.N), parsename(REPLACE(Name,',','.'), t.N))
) AS x(id_new, name_new)
WHERE id_new IS NOT NULL
ORDER BY id_new; -- for presentation only, not required and will slow you down

结果

ID   Name  Comments
---- ----- -----------
1    ABC   HI
2    DEF   HELLO
3    GHI   HELLO
4    JKL   HII
5    M     HEY
6    N     HEY
7    O     HEY

执行计划

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-11
    相关资源
    最近更新 更多