使用动态 sql 旋转两列
Pivotting two columns using dynamic sql
我正在尝试将两个列旋转到行
NO Code Amount
-- ---- -------
1 61 1714.00
1 23 95.79
1 80 31.00
1 61 45.00
2 61 1714.00
2 23 95.79
3 80 31.00
4 61 45.00
4 61 1714.00
4 23 95.79
4 80 31.00
4 61 45.00
我想将代码和金额列动态转换为如下所示,并向列名称添加后缀
NO Code_01 Amount_01 Code_02 Amount_02 Code_03 Amount_03 Code_04 Amount_04
1 61 1714.00 23 95.79 80 31.00 61 45.00
2 61 1714.00 23 95.79 - - - -
...
我开始做一个专栏,但 运行 出错了...对此有什么帮助吗?
DECLARE @cols NVARCHAR(MAX)
,@sql NVARCHAR(MAX)
SET @cols = STUFF((
SELECT DISTINCT ',' + QUOTENAME(CODE)
FROM Table1
ORDER BY 1
FOR XML PATH('')
,TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET @sql = 'SELECT NO, ' + @cols + '
FROM
(
SELECT NO
FROM Table1
) s
PIVOT
(
MAX(Amount) FOR Code IN (' + @cols + ')
) p'
--print(@sql)
EXECUTE(@sql)
使用动态 sql 生成条件聚合语句以通过 row_number()
(按 No
划分)而不是多个枢轴获得 max()
:
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
char(10)+' , '
+ quotename('Code_'+rn)+' = max(case when rn = '+rn+' then Code end)'
+ char(10)+' , '
+ quotename('Amount_'+rn)+' = max(case when rn = '+rn+' then Amount end)'
from (
select No, Code
, rn = convert(varchar(10),row_number() over (partition by No order by Code))
from Table1
) s
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,0,'');
select @sql ='
select No '+@cols+'
from (
select No, Code, Amount
, rn = row_number() over (partition by No order by Code)
from Table1
) sub
group by No';
select @sql;
exec(@sql);
rextester 演示:http://rextester.com/ALTID91433
代码生成:
select No
, [Code_1] = max(case when rn = 1 then Code end)
, [Amount_1] = max(case when rn = 1 then Amount end)
, [Code_2] = max(case when rn = 2 then Code end)
, [Amount_2] = max(case when rn = 2 then Amount end)
, [Code_3] = max(case when rn = 3 then Code end)
, [Amount_3] = max(case when rn = 3 then Amount end)
, [Code_4] = max(case when rn = 4 then Code end)
, [Amount_4] = max(case when rn = 4 then Amount end)
, [Code_5] = max(case when rn = 5 then Code end)
, [Amount_5] = max(case when rn = 5 then Amount end)
from (
select No, Code, Amount
, rn = row_number() over (partition by No order by Code)
from Table1
) sub
group by No
结果:
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
| No | Code_1 | Amount_1 | Code_2 | Amount_2 | Code_3 | Amount_3 | Code_4 | Amount_4 | Code_5 | Amount_5 |
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
| 1 | 23 | 95.79 | 61 | 45.00 | 61 | 1714.00 | 80 | 31.00 | NULL | NULL |
| 2 | 23 | 95.79 | 61 | 1714.00 | NULL | NULL | NULL | NULL | NULL | NULL |
| 3 | 80 | 31.00 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 4 | 23 | 95.79 | 61 | 45.00 | 61 | 45.00 | 61 | 1714.00 | 80 | 31.00 |
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
您可以像这样动态创建 PIVOT
查询。
DECLARE @ColumnNames NVARCHAR(MAX) =''
SELECT @ColumnNames = @ColumnNames + ', ' + QUOTENAME ( 'Code_' + RN ) + ', ' + QUOTENAME ( 'Amount_' + RN )
FROM (SELECT DISTINCT RN = RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) FROM Table1 ) AS T
SET @ColumnNames = STUFF(@ColumnNames,1,1,'')
DECLARE @SqlText NVARCHAR(MAX)
SET @SqlText = 'SELECT * FROM
(SELECT [NO], ''Code_'' + RIGHT(''0'' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Code) Value FROM Table1
UNION ALL
SELECT [NO], ''Amount_'' + RIGHT(''0'' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Amount) Value FROM Table1 ) SRC
PIVOT (MAX(Value) FOR Col IN (' + @ColumnNames + ') ) PVT'
print @SqlText
EXEC sp_executesql @SqlText
生成的查询:
SELECT * FROM
(SELECT [NO], 'Code_' + RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Code) Value FROM Table1
UNION ALL
SELECT [NO], 'Amount_' + RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Amount) Value FROM Table1 ) SRC
PIVOT (MAX(Value) FOR Col IN ( [Code_01], [Amount_01], [Code_02], [Amount_02], [Code_03], [Amount_03], [Code_04], [Amount_04], [Code_05], [Amount_05]) ) PVT
结果:
NO Code_01 Amount_01 Code_02 Amount_02 Code_03 Amount_03 Code_04 Amount_04 Code_05 Amount_05
--- ------- --------- ------- --------- ------- --------- ------- --------- ------- ---------
1 61 1714.00 23 95.79 80 31.00 61 45.00 NULL NULL
2 61 1714.00 23 95.79 NULL NULL NULL NULL NULL NULL
3 80 31.00 NULL NULL NULL NULL NULL NULL NULL NULL
4 61 45.00 61 1714.00 23 95.79 80 31.00 61 45.00
我正在尝试将两个列旋转到行
NO Code Amount
-- ---- -------
1 61 1714.00
1 23 95.79
1 80 31.00
1 61 45.00
2 61 1714.00
2 23 95.79
3 80 31.00
4 61 45.00
4 61 1714.00
4 23 95.79
4 80 31.00
4 61 45.00
我想将代码和金额列动态转换为如下所示,并向列名称添加后缀
NO Code_01 Amount_01 Code_02 Amount_02 Code_03 Amount_03 Code_04 Amount_04
1 61 1714.00 23 95.79 80 31.00 61 45.00
2 61 1714.00 23 95.79 - - - -
...
我开始做一个专栏,但 运行 出错了...对此有什么帮助吗?
DECLARE @cols NVARCHAR(MAX)
,@sql NVARCHAR(MAX)
SET @cols = STUFF((
SELECT DISTINCT ',' + QUOTENAME(CODE)
FROM Table1
ORDER BY 1
FOR XML PATH('')
,TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET @sql = 'SELECT NO, ' + @cols + '
FROM
(
SELECT NO
FROM Table1
) s
PIVOT
(
MAX(Amount) FOR Code IN (' + @cols + ')
) p'
--print(@sql)
EXECUTE(@sql)
使用动态 sql 生成条件聚合语句以通过 row_number()
(按 No
划分)而不是多个枢轴获得 max()
:
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
char(10)+' , '
+ quotename('Code_'+rn)+' = max(case when rn = '+rn+' then Code end)'
+ char(10)+' , '
+ quotename('Amount_'+rn)+' = max(case when rn = '+rn+' then Amount end)'
from (
select No, Code
, rn = convert(varchar(10),row_number() over (partition by No order by Code))
from Table1
) s
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,0,'');
select @sql ='
select No '+@cols+'
from (
select No, Code, Amount
, rn = row_number() over (partition by No order by Code)
from Table1
) sub
group by No';
select @sql;
exec(@sql);
rextester 演示:http://rextester.com/ALTID91433
代码生成:
select No
, [Code_1] = max(case when rn = 1 then Code end)
, [Amount_1] = max(case when rn = 1 then Amount end)
, [Code_2] = max(case when rn = 2 then Code end)
, [Amount_2] = max(case when rn = 2 then Amount end)
, [Code_3] = max(case when rn = 3 then Code end)
, [Amount_3] = max(case when rn = 3 then Amount end)
, [Code_4] = max(case when rn = 4 then Code end)
, [Amount_4] = max(case when rn = 4 then Amount end)
, [Code_5] = max(case when rn = 5 then Code end)
, [Amount_5] = max(case when rn = 5 then Amount end)
from (
select No, Code, Amount
, rn = row_number() over (partition by No order by Code)
from Table1
) sub
group by No
结果:
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
| No | Code_1 | Amount_1 | Code_2 | Amount_2 | Code_3 | Amount_3 | Code_4 | Amount_4 | Code_5 | Amount_5 |
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
| 1 | 23 | 95.79 | 61 | 45.00 | 61 | 1714.00 | 80 | 31.00 | NULL | NULL |
| 2 | 23 | 95.79 | 61 | 1714.00 | NULL | NULL | NULL | NULL | NULL | NULL |
| 3 | 80 | 31.00 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 4 | 23 | 95.79 | 61 | 45.00 | 61 | 45.00 | 61 | 1714.00 | 80 | 31.00 |
+----+--------+----------+--------+----------+--------+----------+--------+----------+--------+----------+
您可以像这样动态创建 PIVOT
查询。
DECLARE @ColumnNames NVARCHAR(MAX) =''
SELECT @ColumnNames = @ColumnNames + ', ' + QUOTENAME ( 'Code_' + RN ) + ', ' + QUOTENAME ( 'Amount_' + RN )
FROM (SELECT DISTINCT RN = RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) FROM Table1 ) AS T
SET @ColumnNames = STUFF(@ColumnNames,1,1,'')
DECLARE @SqlText NVARCHAR(MAX)
SET @SqlText = 'SELECT * FROM
(SELECT [NO], ''Code_'' + RIGHT(''0'' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Code) Value FROM Table1
UNION ALL
SELECT [NO], ''Amount_'' + RIGHT(''0'' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Amount) Value FROM Table1 ) SRC
PIVOT (MAX(Value) FOR Col IN (' + @ColumnNames + ') ) PVT'
print @SqlText
EXEC sp_executesql @SqlText
生成的查询:
SELECT * FROM
(SELECT [NO], 'Code_' + RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Code) Value FROM Table1
UNION ALL
SELECT [NO], 'Amount_' + RIGHT('0' + CONVERT(varchar, ROW_NUMBER() OVER(PARTITION BY [NO] ORDER BY [NO]) ),2) Col, CONVERT(VARCHAR,Amount) Value FROM Table1 ) SRC
PIVOT (MAX(Value) FOR Col IN ( [Code_01], [Amount_01], [Code_02], [Amount_02], [Code_03], [Amount_03], [Code_04], [Amount_04], [Code_05], [Amount_05]) ) PVT
结果:
NO Code_01 Amount_01 Code_02 Amount_02 Code_03 Amount_03 Code_04 Amount_04 Code_05 Amount_05
--- ------- --------- ------- --------- ------- --------- ------- --------- ------- ---------
1 61 1714.00 23 95.79 80 31.00 61 45.00 NULL NULL
2 61 1714.00 23 95.79 NULL NULL NULL NULL NULL NULL
3 80 31.00 NULL NULL NULL NULL NULL NULL NULL NULL
4 61 45.00 61 1714.00 23 95.79 80 31.00 61 45.00