SQL Unpivot行并获取订单号

时间:2018-01-03 14:19:19

标签: sql sql-server pivot unpivot

我有几行诊断代码。如何将列拆分为行?我尝试使用以下查询进行取消转换,但我不确定如何获取DX_Order这是列号,例如DX01DX_Order = 1。我相信UNPIVOT.

会处理NULL

当前表格

+----+------+-------+-------+------+----+------+
| ID | Name | DX01  | DX02  | DX03 | .. | DX25 |
+----+------+-------+-------+------+----+------+
|  1 | John | 426S3 | G2634 | NULL | .. | NULL |
+----+------+-------+-------+------+----+------+

预期结果

+----+------+----------+-------+
| ID | Name | DX_Order |  DX   |
+----+------+----------+-------+
|  1 | John |        1 | 426S3 |
|  1 | John |        2 | G2634 |
+----+------+----------+-------+

查询

SELECT ID, Name, DX
FROM
(
  SELECT ID, Name, DX01, DX02, DX03...DX25
  FROM dbo.Table
) AS cp
UNPIVOT 
(
  DX FOR DXs IN (DX01, DX02, DX03....DX25)
) AS up;

5 个答案:

答案 0 :(得分:2)

使用Cross Apply代替unpivot。除了DX0n列,您还可以添加订单列

SELECT ID, Name, DX_Order, DX
  FROM dbo.Table
  Cross apply (values (DX01,1),(DX02,2),(DX03,3),...(DX025,25)) cs (DX, DX_Order)
  Where DX is not null

如果NULL列中有一些DX0n值且仍然希望DX_Order为序列,那么

SELECT ID,
       NAME,
       DX_Order = Row_number()OVER(ORDER BY DX_Order),
       DX
FROM   (SELECT ID, NAME, DX_Order, DX
        FROM   dbo.Table
               CROSS apply (VALUES (DX01,1),(DX02,2),(DX03,3),..(DX025,25)) cs (DX, DX_Order)
        WHERE  DX IS NOT NULL) a 

答案 1 :(得分:1)

Pரதீப்解决方案将是我的第一个选择(+1),并且肯定更具性能。

但是,以下内容将动态地取消您的数据,而无需指定所有字段,也无需实际使用动态SQL

示例

Declare @YourTable table (ID int,Name varchar(50),DX01 varchar(50),DX02 varchar(50),DX03 varchar(50))
Insert Into @YourTable values
(1,'John','426S3','G2634',null)


Select A.ID
      ,A.Name
      ,DX_Order= C.ColNr
      ,DX = C.Value
 From @YourTable A
 Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
 Cross Apply (
                Select ColNr = row_number() over (order by (Select null))
                      ,Field = a.value('local-name(.)','varchar(100)')
                      ,Value = a.value('.','varchar(max)') 
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') not in ('ID','Name')
             ) C

<强>返回

ID  Name    DX_Order    DX
1   John    1           426S3
1   John    2           G2634

答案 2 :(得分:0)

请尝试这样。

SELECT ID,DX_Order,DX
       FROM dbo.TableN
                CROSS apply 
(VALUES ([DX01],1),([DX02],2)) cs (DX,DX_Order)
WHERE DX IS NOT NULL

答案 3 :(得分:0)

您也可以通过执行动态SQL查询来执行此操作。

<强>查询

declare @sql as varchar(max);

select @sql = stuff((
        select ' union all select [ID], [Name], cast(replace(' 
        + char(39) + [column_name] + char(39) + ', ' + char(39) 
        + 'DX' + char(39) + ',' + char(39) + char(39) + ') as int) as [DX_Order],
        case when [' + [column_name] + '] is not null then [' + [column_name] 
        + '] else null end as [DX] from [your_table_name]'
        from information_schema.columns
        where table_name = 'your_table_name'
        and [column_name] like 'DX%'
        order by ordinal_position
        for xml path(''), type
    ).value('.', 'nvarchar(max)')
    , 1, 11, ''
);

select @sql = 'select t.* from (' + @sql + ') t where t.[DX] is not null;';

exec(@sql); 

答案 4 :(得分:0)

示例数据创建

IF OBJECT_ID('dbo.temp') iS NOT NULL
DROP TABLE temp
;With cte(ID , Name , DX01  , DX02  , DX03 , DX25 )
AS
( SELECT 1 , 'John' , '426S3' , 'G2634' , NULL,NULL 
)
SELECT * INTO temp FROM cte

使用Dynamic Sql,当我们有n列

时,我们可以得到预期的结果
DECLARE @SQlColumn nvarchar(max)
        ,@SQl nvarchar(max)


SELECT @SQlColumn= STUFF((SELECT ', '+Columnname  FROM
                (
            SELECT  '( '+ 'CAST('+QUOTENAME(COLUMN_NAME)+' AS VARCHAR(30)),CAST(REPLACE('''+COLUMN_NAME+''+''','''+'DX'+''',''' +''''+') AS VARCHAR(30)))'  AS Columnname
                FROM INFORMATION_SCHEMA.COLUMNS 
                WHERE TABLE_NAME='temp' AND COLUMN_NAME <>'Id' AND COLUMN_NAME <>'Name'
                )dt FOR XML PATH ('')),1,1,'')

SET @SQl='  SELECT ID
                 ,Name
                 ,DX
                 ,DX_Order FROM temp 
            CROSS APPLY (VALUES '+ @SQlColumn + ') dt (DX,DX_Order) WHERE DX IS NOT NULL'
PRINT @SQl
EXEC(@SQl)

结果

  ID    Name    DX_Order    DX
  ------------------------------
   1    John    01         426S3
   1    John    02         G2634