【问题标题】:Putting comma separated values into separate or different columns将逗号分隔的值放入单独或不同的列中
【发布时间】:2017-09-16 14:01:33
【问题描述】:

我有一个表和值,如下所示

create table #example(id int primary key identity, cols varchar(255))
insert into #example(cols) values('HI,HELLO,BYE,TC')
insert into #example(cols) values('WHAT,ARE,YOU,DOING,HERE')

我需要如图所示的结果输出

注意:值没有限制,即动态

【问题讨论】:

  • 创建 2 个表,您可以更轻松地执行此操作...
  • 你使用的是哪个版本的sql server?
  • 拆分为行,然后旋转。下次不要犯同样的错误,使用单列存储多个项目。
  • 正如 Zohar 所建议的,这更自然地建模为多个 。如果您必须旋转此类动态数据,通常最好留给表示层(应用程序/报告构建器)。您应该认识到一个基本事实 - SQL 不是电子表格,行和列是根本不同的。所有工具将您推向的自然表示是一组固定的列和可变数量的行。

标签: sql sql-server


【解决方案1】:

这是你所期待的

架构:

CREATE TABLE #EXAMPLE(ID INT PRIMARY KEY IDENTITY, COLS VARCHAR(255))
INSERT INTO #EXAMPLE(COLS) VALUES('HI,HELLO,BYE,TC')
INSERT INTO #EXAMPLE(COLS) VALUES('WHAT,ARE,YOU,DOING,HERE')

将这些逗号分隔的值拆分为行并应用枢轴

SELECT * FROM (
SELECT id
, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT 1)) AS ID2
, SPLT.CLMS.value('.','VARCHAR(MAX)') AS LIST FROM ( 
select id
, CAST( '<M>'+REPLACE(cols,',','</M><M>')+'</M>' AS XML) AS XML_COL from #example E
)E
CROSS APPLY  E.XML_COL.nodes('/M') AS SPLT(CLMS)
)A
PIVOT
(
    MAX(LIST) FOR ID2 IN ([1],[2],[3],[4],[5])
)PV

你会得到结果

+----+------+-------+-----+-------+------+
| id |  1   |   2   |  3  |   4   |  5   |
+----+------+-------+-----+-------+------+
|  1 | HI   | HELLO | BYE | TC    | NULL |
|  2 | WHAT | ARE   | YOU | DOING | HERE |
+----+------+-------+-----+-------+------+

编辑:

现在您需要进行动态枢轴,因为值没有限制。

DECLARE @COLS VARCHAR(MAX)='', @QRY VARCHAR(MAX)='';


SELECT @COLS =@COLS+'['+CAST( ID2 AS VARCHAR(10))+'],' FROM (
SELECT  DISTINCT ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT 1)) AS ID2  FROM ( 
select id, CAST( '<M>'+REPLACE(cols,',','</M><M>')+'</M>' AS XML) AS XML_COL from #example E
)E
CROSS APPLY  E.XML_COL.nodes('/M') AS SPLT(CLMS)
)A

SELECT @COLS = LEFT(@COLS,LEN(@COLS)-1)


SELECT @QRY =
'
SELECT * FROM (
SELECT id
, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT 1)) AS ID2
, SPLT.CLMS.value(''.'',''VARCHAR(MAX)'') AS LIST FROM ( 
select id, CAST( ''<M>''+REPLACE(cols,'','',''</M><M>'')+''</M>'' AS XML) AS XML_COL from #example E
)E
CROSS APPLY  E.XML_COL.nodes(''/M'') AS SPLT(CLMS)
)A
PIVOT
(
    MAX(LIST) FOR ID2 IN ('+@COLS+ ')
)PV'

EXEC( @QRY)

【讨论】:

  • 这几乎是正确的。问题是枢轴必须是动态的,因为 OP 声明源列中的项目数量没有限制。
  • @ZoharPeled 谢谢。是的,OP 需要动态支点。
  • 我不需要检查它。我确信它适用于提供的示例数据。但是,如果您添加具有 6 个或更多值的行,它将不适用。
【解决方案2】:

基于split string 然后pivot 表的动态版本

架构:

create table #example(id int primary key identity, cols varchar(255))
insert into #example(cols) values('HI,HELLO,BYE,TC')
insert into #example(cols) values('WHAT,ARE,YOU,DOING,HERE')

计算列轴

-- Calculate dynamic columns
;WITH temps AS 
(
  SELECT sd.* ,CAST('<x>' + replace(sd.cols, ',', '</x><x>') + '</x>' as xml) AS xmlText
  FROM #example sd
),
temps1 AS
(
   SELECT t.Id, t.cols, v.x.value('.','varchar(50)') AS Value
   FROM temps t
   CROSS APPLY 
     t.xmlText.nodes('/x') AS v(x)
)
SELECT @ColumnPivot =  STUFF((SELECT DISTINCT CONCAT(',COL',row_number() OVER(PARTITION BY t.id ORDER BY t.Value)) FROM temps1 t FOR XML PATH('')), 1,1,'')

PRINT @ColumnPivot

然后PIVOT

 DECLARE @query nvarchar(max) = 
   CONCAT(N';WITH temps AS 
   (
      SELECT sd.* ,CAST(''<x>'' + replace(sd.cols, '','', ''</x><x>'') + ''</x>'' as xml) AS xmlText
      FROM #example sd
   ),
   temps1 AS
   (
      SELECT t.Id, t.cols, v.x.value(''.'' , ''varchar(50)'') AS Value
      FROM temps t
      CROSS APPLY 
         t.xmlText.nodes(''/x'') AS v(x)
   ),
   temps2 AS
   (
      SELECT t.* , CONCAT(''COL'',row_number() OVER(PARTITION BY t.id ORDER BY (select 1))) AS ColGroup
      FROM temps1 t
   )',
    N'SELECT Id, cols, ' , @ColumnPiVot,
  ' FROM
    (
       select * from temps2
    ) AS src
  PIVOT 
    (MAX(Value) FOR ColGroup IN (',@ColumnPiVot,')) AS pvt')
  PRINT @query
  exec sp_executesql  @query

DROP TABLE #example

演示链接:Rextester

【讨论】:

    【解决方案3】:
              DECLARE @COLS AS NVARCHAR(MAX),
        @QUERY  AS NVARCHAR(MAX);
    
    SET @COLS = STUFF((SELECT DISTINCT ',' + QUOTENAME(C.RN) 
                FROM (SELECT ID,TOKEN,COLS
        ,ROW_NUMBER() OVER (
            PARTITION BY ID ORDER BY (
                    SELECT NULL
                    )
            ) AS RN
    FROM #EXAMPLE
    CROSS APPLY (
        SELECT *
        FROM UDF_SPLITSTRING(COLS, ',')
        ) A) C
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    SET @QUERY = 'SELECT ID,cols, ' + @COLS + ' FROM 
                (
                    SELECT ID,TOKEN,cols
        ,ROW_NUMBER() OVER (
            PARTITION BY ID ORDER BY (
                    SELECT NULL
                    )
            ) AS RN
    FROM #EXAMPLE
    CROSS APPLY (
        SELECT *
        FROM UDF_SPLITSTRING(COLS, '','')
        ) A
    
               ) X
                PIVOT 
                (
                     MAX(TOKEN)
                    FOR rn IN (' + @COLS + ')
                ) P '
    
    
    exec(@QUERY)
    

    输出

    ID  cols                    1       2       3    4       5
    1   HI,HELLO,BYE,TC         HI     HELLO    BYE  TC      NULL
    2   WHAT,ARE,YOU,DOING,HERE WHAT    ARE     YOU  DOING   HERE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 2017-06-22
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多