使用动态 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