SQL 将列转置为具有波动行的行
SQL Transpose Columns to Rows with fluctuating Rows
我正在尝试转置视图中的列和行,但是这些行是每周更改的日期,我似乎无法正常运行。
下面是我的;
Date | Report1 | Report2 |
---------- | ------- | ------- |
2017-07-01 | N/A | Yes |
2017-07-02 | Yes | Yes |
2017-07-03 | N/A | Yes |
2017-07-04 | Yes | Yes |
2017-07-05 | N/A | Yes |
2017-07-06 | NULL | NULL |
2017-07-07 | N/A | N/A |
我希望它看起来像;
Date | 2017-07-01 | 2017-07-02 | 2017-07-03 | 2017-07-04 | 2017-07-05 | 2017-07-06 | 2017-07-07 |
-------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- |
Report1 | N/A | Yes | N/A | Yes | N/A | Null | N/A |
Report2 | Yes | Yes | Yes | Yes | Yes | Null | N/A |
唯一的问题是日期在滚动,因此列名会发生变化。
*还有更多报告,但为简单起见,2 个就足够了
您实际上需要结合使用 UNPIVOT 和 Dynamic PIVOT
IF (OBJECT_ID('tempdb..#unpvt') IS NOT NULL) DROP TABLE #unpvt;
SELECT Report, Val, [Date]
INTO #unpvt
FROM
(
SELECT [Date], [Report1], [Report2]
FROM YourTable
) p
UNPIVOT
(Val FOR Report IN ([Report1], [Report2])
)AS unpvt;
DECLARE @cols AS NVARCHAR(MAX);
DECLARE @sql AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ', ' + QUOTENAME([Date])
FROM YourTable c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,'');
SET @sql = 'SELECT Report, ' + @cols + ' FROM
(
SELECT * FROM #unpvt
) x
PIVOT
(
MAX(Val)
FOR [Date] in (' + @cols + ')
) p ';
EXECUTE(@sql);
以下将动态反透视您的数据,然后 create/execute 动态透视。
使用动态 UNPIVOT,无需指定字段(或 "reports")
此外,使用日期参数(@Date1 和@Date2),您可以指定要透视的所需日期范围
例子
Declare @Date1 varchar(10) = '2017-07-01'
Declare @Date2 varchar(10) = '2017-07-07'
Declare @SQL varchar(max) = '
Declare @XML xml = (Select * from YourTable Where Date Between '''+@Date1+''' and '''+@Date2+''' for XML RAW)
Select *
From (
Select Date = r.value(''@Date'',''Date'')
,Item = attr.value(''local-name(.)'',''varchar(100)'')
,Value = attr.value(''.'',''varchar(max)'')
From @XML.nodes(''/row'') as A(r)
Cross Apply A.r.nodes(''./@*'') AS B(attr)
Where attr.value(''local-name(.)'',''varchar(100)'') not in (''Date'')
) A
Pivot (max([Value]) For [Date] in (' + Stuff((Select Distinct ','+QuoteName(Date)
From YourTable
Where Date Between @Date1 and @Date2
Order By 1
For XML Path('')),1,1,'') + ') ) p'
Exec(@SQL);
--Print @SQL
Returns
我正在尝试转置视图中的列和行,但是这些行是每周更改的日期,我似乎无法正常运行。
下面是我的;
Date | Report1 | Report2 |
---------- | ------- | ------- |
2017-07-01 | N/A | Yes |
2017-07-02 | Yes | Yes |
2017-07-03 | N/A | Yes |
2017-07-04 | Yes | Yes |
2017-07-05 | N/A | Yes |
2017-07-06 | NULL | NULL |
2017-07-07 | N/A | N/A |
我希望它看起来像;
Date | 2017-07-01 | 2017-07-02 | 2017-07-03 | 2017-07-04 | 2017-07-05 | 2017-07-06 | 2017-07-07 |
-------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- |
Report1 | N/A | Yes | N/A | Yes | N/A | Null | N/A |
Report2 | Yes | Yes | Yes | Yes | Yes | Null | N/A |
唯一的问题是日期在滚动,因此列名会发生变化。 *还有更多报告,但为简单起见,2 个就足够了
您实际上需要结合使用 UNPIVOT 和 Dynamic PIVOT
IF (OBJECT_ID('tempdb..#unpvt') IS NOT NULL) DROP TABLE #unpvt;
SELECT Report, Val, [Date]
INTO #unpvt
FROM
(
SELECT [Date], [Report1], [Report2]
FROM YourTable
) p
UNPIVOT
(Val FOR Report IN ([Report1], [Report2])
)AS unpvt;
DECLARE @cols AS NVARCHAR(MAX);
DECLARE @sql AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ', ' + QUOTENAME([Date])
FROM YourTable c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,'');
SET @sql = 'SELECT Report, ' + @cols + ' FROM
(
SELECT * FROM #unpvt
) x
PIVOT
(
MAX(Val)
FOR [Date] in (' + @cols + ')
) p ';
EXECUTE(@sql);
以下将动态反透视您的数据,然后 create/execute 动态透视。
使用动态 UNPIVOT,无需指定字段(或 "reports")
此外,使用日期参数(@Date1 和@Date2),您可以指定要透视的所需日期范围
例子
Declare @Date1 varchar(10) = '2017-07-01'
Declare @Date2 varchar(10) = '2017-07-07'
Declare @SQL varchar(max) = '
Declare @XML xml = (Select * from YourTable Where Date Between '''+@Date1+''' and '''+@Date2+''' for XML RAW)
Select *
From (
Select Date = r.value(''@Date'',''Date'')
,Item = attr.value(''local-name(.)'',''varchar(100)'')
,Value = attr.value(''.'',''varchar(max)'')
From @XML.nodes(''/row'') as A(r)
Cross Apply A.r.nodes(''./@*'') AS B(attr)
Where attr.value(''local-name(.)'',''varchar(100)'') not in (''Date'')
) A
Pivot (max([Value]) For [Date] in (' + Stuff((Select Distinct ','+QuoteName(Date)
From YourTable
Where Date Between @Date1 and @Date2
Order By 1
For XML Path('')),1,1,'') + ') ) p'
Exec(@SQL);
--Print @SQL
Returns