Pivot sql convert rows to columns

前端 未结 2 1980
予麋鹿
予麋鹿 2021-01-26 08:03

The below query get the following out put.

Service Date  Product1 Product2 
01/Jun/2015    1           3
02/Jun/2015    2           5

Instead o

相关标签:
2条回答
  • 2021-01-26 08:20

    This is how it's done using plain ANSI SQL.

    First, you need to pivot vertically - UNPIVOT in TRANSACT-SQL speak - which you do by CROSS JOINing with a single-column temp table with as many consecutive integers as you have values to "unpivot". You use those integers as indexes in a CASE WHEN expression for the values.

    Then, you re-pivot, using a SUM(CASE WHEN ...) expression, and GROUP BY the column whose values you want to see vertically in the first column.

    Here goes:

    WITH
    -- input
    input(Service_Date,Product1,Product2) AS (
              SELECT DATE '2015-06-01',1,3
    UNION ALL SELECT DATE '2015-06-02',2,5
    )          
    ,
    -- start vertical pivot: two integers
    two_ints(idx) AS (SELECT 1 UNION ALL SELECT 2)
    ,
    -- vertical pivot: CROSS JOIN input with two integers
    vert_pivot AS (
    SELECT
      Service_Date
    , idx
    , 'Product'||CAST(idx AS CHAR(1)) AS product
    , CASE idx WHEN 1 THEN Product1 WHEN 2 THEN Product2 END AS qty
    FROM input CROSS JOIN two_ints
    )
    -- debug
    -- SELECT * FROM vert_pivot;
    -- Service_Date|idx|product |qty
    -- 2015-06-01  |  1|Product1|  1
    -- 2015-06-01  |  2|Product2|  3
    -- 2015-06-02  |  1|Product1|  2
    -- 2015-06-02  |  2|Product2|  5
    ,
    -- re-pivot horizontally by date
    horiz_pivot_dt AS (
    SELECT
      product
    , SUM(CASE Service_Date WHEN '2015-06-01' THEN qty END) AS "2015-06-01"
    , SUM(CASE Service_Date WHEN '2015-06-02' THEN qty END) AS "2015-06-02"
    FROM vert_pivot
    GROUP BY
      product
    )
    SELECT * FROM horiz_pivot_dt
    ;
    -- result:
    -- product |2015-06-01|2015-06-02
    -- Product1|         1|         2
    -- Product2|         3|         5
    

    by the way: I noted that you only pivoted the "column names" and the first column's values - not the measures. My example above did, and I spent a few minutes trying to find out where my error was ....

    Happy playing ... marco

    0 讨论(0)
  • 2021-01-26 08:25

    Your current query is pivoting product names and grouping the dates. But you need to pivot the dates and group the product names

    Try this way

    DECLARE @cols  AS NVARCHAR(max),
            @query AS NVARCHAR(max)
    

    Find the distinct list of dates instead of product names

    SELECT @cols = Stuff((SELECT ','
                                 + Quotename(CONVERT(char(11), Service_Date, 106))
                          FROM   dbo.Store
                          WHERE  CatID = '2'
                          GROUP  BY CONVERT(char(11), Service_Date, 106)
                          ORDER  BY CONVERT(date, Service_Date)
                          FOR xml PATH (''), TYPE) .value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    

    In pivot for list use the Service_date column instead of Product_Name

    SET @query = 'SELECT Product_Name,'
                 + @cols
                 + ' from ( select Service.Service_Date, Store.Product_Name, Servicelist.ProductQty FROM   dbo.Service INNER JOIN dbo.Servicelist ON dbo.Service.Service_ID = dbo.Servicelist.Service_ID INNER JOIN dbo.Store ON dbo.Servicelist.Pro_ID = dbo.Store.Pro_ID) x pivot ( SUM(ProductQty) for CONVERT(char(11), Service_Date, 106) in ('
                 + @cols + ') ) p '
    
    EXECUTE (@query); 
    
    0 讨论(0)
提交回复
热议问题