SQL 反转行并获取订单号
SQL Unpivot the row and get Order Number
我排了好几个诊断码。如何将列反透视为行?我尝试了以下查询来取消透视,但我不确定如何获取列号 DX_Order
,例如 DX01
、DX_Order
=1。我相信 NULL 由 UNPIVOT.
处理
当前table
+----+------+-------+-------+------+----+------+
| 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;
使用 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
如果 DX0n
列中有一些 NULL
值,而您仍然希望 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
请这样尝试。
SELECT ID,DX_Order,DX
FROM dbo.TableN
CROSS apply
(VALUES ([DX01],1),([DX02],2)) cs (DX,DX_Order)
WHERE DX IS NOT NULL
您也可以通过执行动态 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);
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
Returns
ID Name DX_Order DX
1 John 1 426S3
1 John 2 G2634
示例数据创建
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
我排了好几个诊断码。如何将列反透视为行?我尝试了以下查询来取消透视,但我不确定如何获取列号 DX_Order
,例如 DX01
、DX_Order
=1。我相信 NULL 由 UNPIVOT.
当前table
+----+------+-------+-------+------+----+------+
| 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;
使用 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
如果 DX0n
列中有一些 NULL
值,而您仍然希望 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
请这样尝试。
SELECT ID,DX_Order,DX
FROM dbo.TableN
CROSS apply
(VALUES ([DX01],1),([DX02],2)) cs (DX,DX_Order)
WHERE DX IS NOT NULL
您也可以通过执行动态 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);
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
Returns
ID Name DX_Order DX
1 John 1 426S3
1 John 2 G2634
示例数据创建
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