使用动态 sql 和自定义列名称旋转数据两次

Pivoting Data twice with dynamic sql and custom column names

我有一个简单的 table non-unique 帐号、产品 ID 和数量:

例如:

account|productid|qty
1       100       1
1       100       1.5
1       102       6
2       100       1

我正在尝试将其动态转换为这种结构:

account|product1|qty1|product2|qty2|etc..|etc..
1       100      2.5  102      6    NULL  NULL
2       100      1    NULL     NULL NULL  NULL

其中一些客户可以订购数百种不同的产品,因此尝试 hard-code 事情最终是不可能的。

我已经设法将其转变为 table 之类的

account|100|102
1       2.5 6
2       1   NULL

产品 ID 作为列 headers,

与:

DECLARE @sql AS NVARCHAR(4000)
  , @col AS NVARCHAR(2000);

SELECT  @col = ISNULL(@col + ', ', '') + QUOTENAME(x.productid)
FROM
(
    SELECT DISTINCT
        tp.productid
    FROM    purchases AS tp

) x
;

SET @sql
    = N'SELECT * FROM purchases as p PIVOT ( SUM(qty) FOR [productid] IN (' + @col
      + ')) piv';

SELECT  @sql;

EXEC sys.sp_executesql @sql;

我试图 select 相同的列两次以获得每个列的数量和产品 ID,方法是将我的 select 语句更改为:

@coltest = ISNULL(@col + ', ', '') + (QUOTENAME(x.productid) + ', ' + QUOTENAME(x.productid))

然而,抛出错误“为 'piv' 多次指定了 productid。”

将数据透视到两个单独的 custom-named 递增列的最佳方法是什么?

无需旋转两次。

例子

Declare @SQL varchar(max) = '
Select *
 From (
        Select A.Account
              ,B.*
         From  (Select Account
                      ,ProductID
                      ,Qty = sum(Qty)
                      ,RN=Row_Number() over (Partition By Account Order by ProductID)
                 From  YourTable
                 Group By Account,Productid
               ) A
         Cross Apply (values (''qty''+cast(RN as varchar(25)),cast(Qty as varchar(100)))
                            ,(''product''+cast(RN as varchar(25)),cast(productid as varchar(100)))
                     ) B (Item,Value)

      ) A
 Pivot (max([Value]) For [Item] in (' + Stuff((Select Distinct ','+QuoteName('product'+ColNr) 
                                                              +','+QuoteName('qty'+ColNr) 
                                               From (Select Distinct ColNr=cast(Row_Number() over (Partition By Account,ProductID Order by (Select NULL)) as varchar(25)) From  YourTable ) A  
                                               Order By 1 
                                               For XML Path('')),1,1,'')  + ') ) p'
Exec(@SQL);
Print @SQL

Returns

如果它有助于可视化 - 子查询产生