SQL Server 2008 R2 - Dynamic Pivot/Unpivot with (moving) Dates

无人久伴 提交于 2019-12-11 03:05:38

问题


I have posted a pivot question before and it was answered. However, this particular case requires dates as the headers and the dates will change (and be unknown) each time the pivot is generated. I believe I need dynamic pivot/unpivot based on a few samples but I cannot figure the syntax out.

Here is the table:

CREATE TABLE [dbo].[PhaseFlowChart](
    [pfckey] [int] NULL,
    [hourlykey] [bigint] NULL,
    [daykey] [bigint] NULL,
    [weekkey] [int] NULL,
    [monthkey] [int] NULL,
    [bbkey] [int] NULL,
    [Day] [varchar](100) NULL,
    [Date] [varchar](100) NULL,
    [Bull Bear Gap] [varchar](100) NULL,
    [Monthly] [varchar](100) NULL,
    [Weekly] [varchar](100) NULL,
    [Daily] [varchar](100) NULL,
    [Hour 1] [varchar](100) NULL,
    [Hour 2] [varchar](100) NULL,
    [Hour 3] [varchar](100) NULL,
    [Hour 4] [varchar](100) NULL,
    [Hour 5] [varchar](100) NULL,
    [Hour 6] [varchar](100) NULL,
    [Hour 7] [varchar](100) NULL
) ON [PRIMARY]

I do not need any of the 'key' columns in the output. Therefore here is a simple select on the table:

select [DAY],[Date],[Bull Bear Gap],[Monthly],[Weekly],[Daily],[Hour 1],[Hour 2],[Hour 3],[Hour 4],[Hour 5],[Hour 6],[Hour 7] 
from PhaseFlowChart
order by pfckey asc

Here is the output from the above:

I want the output (dynamic pivot/unpivot?) to look like this (and again, the dates will be different each time this is generated which is daily):

Finally, I found this sql on the web but after days of manipulating the syntax I cannot figure out how to port it to meet my needs.

CREATE TABLE #yt
    ([ID] int, [expense] int, [revenue] int, [date] datetime)
;

INSERT INTO #yt
    ([ID], [expense], [revenue], [date])
VALUES
    (1, 43, 45, '2012-12-31 00:00:00'),
    (2, 32, 32, '2013-01-01 00:00:00'),
    (3, 64, 56, '2013-01-31 00:00:00'),
    (4, 31, 32, '2013-03-03 00:00:00')

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

select @cols = STUFF((SELECT ',' + QUOTENAME(c.col+'_'+convert(varchar(10), #yt.date, 110)) 
                    from #yt
                    cross apply
                    (
                      select 'expense' col union all
                      select 'revenue'
                    ) c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id,' + @cols + ' 
            from
            (
              select id, 
                col+''_''+convert(varchar(10), date, 110) new_col, 
                value
              from #yt
              unpivot
              (
                value
                for col in (expense, revenue)
              ) un
            ) src
            pivot 
            (
                sum(value)
                for new_col in (' + @cols + ')
            ) p '

execute(@query);

Any/all help is greatly appreciated.


回答1:


You first need to UNPIVOT our columns and use DENSE_RANK() to give you something to pivot on later. Put this result into a temp table so that you can get a comma seperated list of the DESNSE_RANK columns. Then create a UNION so that Day and Date are part of the same column as what was unpivoted. This can be put in a global temp table for use in the dynamic SQL. Create a variable that will store the list of columns and build the dynamic SQL and execute it.

A full example (obviously don't go dropping the PhaseFlowChart table)

-- pre-cleanup
IF OBJECT_ID('[dbo].[PhaseFlowChart]') IS NOT NULL
    DROP TABLE [dbo].[PhaseFlowChart]
GO

IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
    DROP TABLE #tmp
GO

IF OBJECT_ID('tempdb..##tmp') IS NOT NULL
    DROP TABLE ##tmp
GO

-- setup table and data
CREATE TABLE [dbo].[PhaseFlowChart](
    [pfckey] [int] NULL,
    [hourlykey] [bigint] NULL,
    [daykey] [bigint] NULL,
    [weekkey] [int] NULL,
    [monthkey] [int] NULL,
    [bbkey] [int] NULL,
    [Day] [varchar](100) NULL,
    [Date] [varchar](100) NULL,
    [Bull Bear Gap] [varchar](100) NULL,
    [Monthly] [varchar](100) NULL,
    [Weekly] [varchar](100) NULL,
    [Daily] [varchar](100) NULL,
    [Hour 1] [varchar](100) NULL,
    [Hour 2] [varchar](100) NULL,
    [Hour 3] [varchar](100) NULL,
    [Hour 4] [varchar](100) NULL,
    [Hour 5] [varchar](100) NULL,
    [Hour 6] [varchar](100) NULL,
    [Hour 7] [varchar](100) NULL
) ON [PRIMARY]

INSERT INTO [dbo].PhaseFlowChart 
    ([Day], [Date], [Bull Bear Gap], Monthly, Weekly, Daily, 
        [Hour 1], [Hour 2], [Hour 3], [Hour 4], [Hour 5], [Hour 6], [Hour 7])
VALUES
('MON', '20130101', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1', 'P1'),
('TUE', '20130102', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2', 'P2'),
('WED', '20130103', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3', 'P3'),
('THU', '20130104', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4', 'P4'),
('FRI', '20130105', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5', 'P5'),
('SAT', '20130106', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6', 'P6'),
('SUN', '20130107', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7', 'P7')
GO

-- unpivot the columns into 'categories'
SELECT [Day], [Date], [Value], [Category], 
    DENSE_RANK() OVER (ORDER BY CAST([Date] AS DATE)) dr 
INTO #tmp
FROM PhaseFlowChart pfc
UNPIVOT (
    Value FOR Category IN ([Bull Bear Gap], Monthly, Weekly, Daily, 
                            [Hour 1], [Hour 2], [Hour 3], [Hour 4], 
                                [Hour 5], [Hour 6], [Hour 7])

) upiv

-- create a global temp table for use later
SELECT *
INTO ##tmp
FROM (
      -- union data into single category column
    SELECT 'Day' Category, [Day] Value, dr, 1 o FROM #tmp
    UNION ALL
    SELECT 'Date' Category, [Date] Value, dr, 2 o FROM #tmp
    UNION ALL
    SELECT [Category], Value, dr, 3 o FROM #tmp
) t

-- get a comma seperated list of columns for the PIVOT
DECLARE @cols VARCHAR(MAX) = 
STUFF(CAST((SELECT ',' + QUOTENAME(dr)
       FROM (
           SELECT DISTINCT dr
           FROM #tmp
       ) t
       ORDER BY dr
       FOR XML PATH(''), TYPE
      ) AS VARCHAR(MAX)),1,1,'')

-- create and execute the sql
DECLARE @sql VARCHAR(MAX) = '
    SELECT Category, ' + @cols + '
    FROM ##tmp
    PIVOT (
        MAX([Value])
        FOR dr IN (' + @cols + ')
    ) piv   
      ORDER BY o, CASE Category 
                    WHEN ''Daily'' THEN 4
                    WHEN ''Weekly'' THEN 3
                    WHEN ''Monthly'' THEN 2
                    WHEN ''Bull Bear Gap'' THEN 1
                    ELSE 5 END, Category
'

EXEC(@sql)


来源:https://stackoverflow.com/questions/19614856/sql-server-2008-r2-dynamic-pivot-unpivot-with-moving-dates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!