Tiawy
Tiawy

Reputation: 175

T-SQL Converting N number of rows to columns

I am look for a good performing T-SQL query to give a large number of Rows N number of columns. But the number of columns will not be the same for each row.

For instance - i have an ordertable like the following with about 1 million rows.

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

Each order can have N number of orderlines.

My orderline table has about 1.5 million rows;

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

I want an endresult like the following:

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

The number of orderlines can be large (like 50) for each order.

I guess i could use subselects but that would require N-number of subselects - and that would perform very poorly

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

Another option could perhaps be pivoting. But as I see it - it is not "traditional" pivoting - it would be dynamic pivoting.

But I'm unsure how that would look and perform?

Upvotes: 0

Views: 91

Answers (2)

John Cappelletti
John Cappelletti

Reputation: 82020

If you need to go dynamic

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);

Returns

enter image description here

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1271151

I would recommend conditional aggregation:

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;

I wouldn't expect your version to work, unless you have a table called o. The proper syntax would be:

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

Upvotes: 1

Related Questions