简体   繁体   中英

T-SQL Rows to Columns: Pivoting with multiple column aggregates

For example i have the following table:

CodInt          DocType         Qty (+)             Qty (-)             TotalCost (+)       TotalCost (-)
-----------------------------------------------------------------------------------------------------------
0208020015      2               NULL                -3.000000000        NULL                130.05000
0208020015      3               13056.000000000     79.000000000        547711.24000        3220.83000
0208020015      5               2.000000000         NULL                81.54000            NULL
0208020015      6               NULL                -11444.000000000    NULL                489120.75000

I need to group everything in a single row. So in the end I need the table to be CodInt + 24 Columns, 4 columns for each DocType (There's a total of 6 DocTypes).

I know i can probably do it with inner joins easily, but i wanted to know if there was a more simple/understandable way to do it since the inner join tend to be somewhat big. I read about a PIVOT clause but i don't think i can use it in this case or haven't understood completely how it works.

Example of what I'm looking for (shortened, there would still be 16 more columns):

CodInt          Qty1 (+)            Qty1 (-)        TotalCost1 (+)  TotalCost1 (-)  Qty2 (+)            Qty2 (-)            TotalCost2 (+)  TotalCost2 (-) .........
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
0208020015      NULL                NULL            NULL            NULL            NULL                -3.000000000        NULL            130.05000      .........

So my question is this: how can I group everything by CodInt , multiply the number of columns for each doctype and place the information of the columns Qty and TotalCost on the new columns?

What you need to do is to UNPIVOT, and then PIVOT your data. Please, read this documentation: Using PIVOT and UNPIVOT .

Edition for the comments: pivoting with multiple aggregates

As I can see from the comments, the only problem that poses this case is that it's needed to PIVOT, aggregating four different columns. To solve this problem it's only necessary to take two additional steps, before the final pivot:

  1. unpivot the columns to aggregate so that they move from the columns to the rows: in this case: [Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)]
  2. concatenate the names of the columns which has been unpivoted to the rows with the other pivoting column ( DocType ), thus obtaining all the combinations like [Qty (+) 1], [Qty (+) 2], [Qty (+) 3] , etc.

You can see it working in this fiddle , and have the full code and explanations down here:

First step: unpivot

With this query you move the columns [Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)] to different rows, to the new Name column

SELECT *
FROM 
    (SELECT 
        CodInt, DocType, [Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)] 
    FROM Test) Orig
UNPIVOT
    ( Value FOR Name IN 
        ([Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)])
    ) UnPiv

And you get something like this:

CodInt   DocType  Value  Name
0208215  2         -3    Qty (-)
0208215  2        130    TotalCost (-)

Second step: get the names for the final aggregates

It's just the same query as before, but, in the select list, instead of select * , concatenate the Name and DocType columns, like this:

SELECT 
    CodInt, 
    CAST(Name AS VARCHAR(20)) + ' ' + CAST(DocType AS VARCHAR(20)) Name,
    Value

At this point you get results that look like this:

CodInt   Name               Value
0208215  Qty (-) 2          -3
0208215  TotalCost (-) 2    130

Third step, pivot the results

Now that you have all the desired columns in their independent rows, you simply have to pivot them. The final query looks like this ( the use of the CTE is for readability, is optional ):

WITH Unpivoted AS (
    SELECT 
        CodInt, 
        CAST(Name AS VARCHAR(20)) + ' ' + CAST(DocType AS VARCHAR(20)) Name,
        Value
    FROM 
        ( SELECT 
            CodInt, DocType, [Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)] 
        FROM Test ) UnPivSource
        UNPIVOT
        ( Value FOR Name IN 
            ([Qty (+)], [Qty (-)], [TotalCost (+)], [TotalCost (-)])
        ) UnPiv
)
SELECT * FROM
( SELECT CodInt, Name, Value FROM Unpivoted ) PivotSource
PIVOT 
(SUM(Value) FOR NAME IN
    (
    [Qty (+) 1], [Qty (+) 2], [Qty (+) 3], [Qty (+) 4], [Qty (+) 5], [Qty (+) 6], 
    [Qty (-) 1], [Qty (-) 2], [Qty (-) 3], [Qty (-) 4], [Qty (-) 5], [Qty (-) 6],
    [TotalCost (+) 1], [TotalCost (+) 2], [TotalCost (+) 3], 
    [TotalCost (+) 4], [TotalCost (+) 5], [TotalCost (+) 6], 
    [TotalCost (-) 1], [TotalCost (-) 2], [TotalCost (-) 3], 
    [TotalCost (-) 4], [TotalCost (-) 5], [TotalCost (-) 6]
    )
) Pivoted

You get the final result, like this:

CodInt   Qty (+) 1  Qty (+) 2  Qty (+) 3  Qty (+) 4  Qty (+) 5  Qty (+) 6  Qty (-) 1  Qty (-) 2  Qty (-) 3  Qty (-) 4  Qty (-) 5  Qty (-) 6  TotalCost (+) 1  TotalCost (+) 2  TotalCost (+) 3  TotalCost (+) 4  TotalCost (+) 5    TotalCost (+) 6  TotalCost (-) 1  TotalCost (-) 2  TotalCost (-) 3  TotalCost (-) 4  TotalCost (-) 5  TotalCost (-) 6
0208215  NULL       NULL       13056      NULL       2          NULL       NULL       -3         79         NULL       NULL       -11444     NULL             NULL             547711           NULL             82                 NULL             NULL             130              3221             NULL             NULL             489121
0208216  NULL       -8         127        NULL       NULL       928283     NULL       NULL       NULL       NULL       124        24         NULL             4567             2519             NULL             NULL               9292993          NULL             NULL             84               NULL             NULL             NULL

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM