T-SQL将N个行转换为列

时间:2017-01-05 13:07:49

标签: sql sql-server

我正在寻找一个性能良好的T-SQL查询,以提供大量行数N列。但每行的列数不一样。

例如 - 我有一个像下面这样约有100万行的订单。

Order
OrderID   Date      
========  ========  
1         20160102  
2         20160402 

每个订单可以有N个订单。

我的订单行表约有150万行;

OrderLine 
OrderID   OrderLine   ProductID     Amount
========  ========    ==========    ==========
1         1           3245          299.00
2         1           9876          799.00
2         2           5466          899.00
2         3           7752          599.00

我想要一个像以下一样的结果:

OrderID   Date     ProductID1  Amount1  ProductID2  Amount2  ProductID3  Amount3       
========  ======== ==========  =======  ==========  =======  ==========  =======
1         20160102  3245        299.00    
2         20160402  9876        799.00   5466        899.00    7752       599.00    

每个订单的订单数量可能很大(如50)。

我想我可以使用子选择,但这需要N个子选择 - 而且表现非常糟糕

SELECT 
 OrderID,
 Date,
 (SELECT ProductID FROM ORDERLINE OI JOIN O ON O.OrderID=OI.OrderID WHERE ORDERLINE=1) AS ProductID1,
 (SELECT Amount    FROM ORDERLINE OI JOIN O ON O.OrderID=OI.OrderID WHERE ORDERLINE=1) AS Amount1,
...
 (SELECT ProductID FROM ORDERLINE OI JOIN O ON O.OrderID=OI.OrderID WHERE ORDERLINE=N) AS ProductIDN,
 (SELECT Amount    FROM ORDERLINE OI JOIN O ON O.OrderID=OI.OrderID WHERE ORDERLINE=N) AS AmountN

FROM 
ORDER O

另一个选择可能是转动。 但正如我所看到的那样 - 它不是“传统的”转动 - 它将是动态的转动。

但是我不确定那会是什么样子和表演?

2 个答案:

答案 0 :(得分:1)

我建议使用条件聚合:

SELECT o.OrderID, o.Date,
       MAX(CASE WHEN ol.orderline = 1 THEN ProductId END) as ProductId1,
       MAX(CASE WHEN ol.orderline = 1 THEN Amount END) as Amount1,
       MAX(CASE WHEN ol.orderline = 2 THEN ProductId END) as ProductId2,
       MAX(CASE WHEN ol.orderline = 2 THEN Amount END) as Amount2,
       . . .
FROM ORDER O JOIN
     ORDERLINE OI
     ON O.OrderID = OI.OrderID
GROUP BY o.OrderID, o.Date;

除非你有一个名为o的表,否则我不希望你的版本有效。正确的语法是:

(SELECT ProductID FROM ORDERLINE OI WHERE O.OrderID = OI.OrderID AND ORDERLINE = 1) AS ProductID1,

答案 1 :(得分:1)

如果你需要动态

Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(concat('ProductID',OrderLine))+','+ QuoteName(concat('Amount',OrderLine)) From OrderLine  Order by 1 For XML Path('')),1,1,'') 
Select  @SQL = '
Select [OrderID],[Date],' + @SQL + '
From (
        Select A.OrderID
              ,A.Date
              ,C.*
        From   [Order] A
        Join   OrderLine B on (A.OrderID=B.OrderID)
        Cross  Apply (Values (concat(''ProductID'',B.OrderLine),cast(B.ProductID as varchar(25)))
                            ,(concat(''Amount''   ,B.OrderLine),cast(B.Amount as varchar(25)))
                      ) C (Item,Value)

     ) A
 Pivot (max(Value) For [Item] in (' + @SQL + ') ) p'
Exec(@SQL);

返回

enter image description here