Динамическая месячная сводная таблица - PullRequest
0 голосов
/ 07 мая 2018

У меня есть таблица счетов, из которой я хочу создать скользящую месячную динамическую сводную таблицу. Я хочу, чтобы текущий месяц был месяцем "1", а этот месяц прошлого года - месяцом "13"

Пример данных:

INVOICEDATE | ITEMCODE | UNITS
2018-05-07  | 123456   | 20
2018-05-04  | 123456   | 5
2018-04-07  | 123456   | 10
....
2017-05-25  | 123456   | 50

Желаемый вывод:

ITEMCODE  | 01 | 02 | .... | 13
123456    | 25 | 10 | .... | 50

Я начал со следующего, но застрял с номером нумерации / заказа месяца, особенно с месяцем прошлого года, переходящим в тот же месяц этого года.

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX), 
@NulltoZero nvarchar(max) 

select @cols =   STUFF((SELECT distinct ',' +  
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) [Month]
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) 
order by [Month] DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') 
,1,1,'') 


select  @NulltoZero =  STUFF((SELECT distinct ',ISNULL(' +  
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2))  
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) 
order by ',ISNULL(' +  
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2))  DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') 
,1,1,'') 


set @query = 'SELECT itemcode, ' + @NulltoZero + ' from 
(
Select ARD.itemcode
,(12 + DATEPART(MONTH, GETDATE()) - DATEPART(MONTH, invoicedate)) % 12 + 1 [MONTH]
,cast(ISNULL(quantityshipped*[UnitOfMeasureConvFactor],0) as int) as units
FROM [MAS_RDP].[dbo].[AR_InvoiceHistoryDetail] ARD 
inner join MAS_RDP..AR_InvoiceHistoryHeader ARH on ARD.InvoiceNo = ARH.InvoiceNo and ARD.HeaderSeqNo = ARH.HeaderSeqNo
inner join MAS_RDP..CI_Item CI on ARD.Itemcode = CI.itemcode and CI.Inactiveitem = ''N'' and CI.itemcode not like ''2%'' and len(ci.itemcode) = 6
inner join MAS_RDP..IM_Itemwarehouse IMW on ARD.itemcode = IMW.itemcode and IMW.warehousecode = ''000'' and imw.udf_is_stocked = ''Y''
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
) x
pivot (sum( units  ) for month in (' + @cols + ') ) p 
order by itemcode'
execute(@query)

1 Ответ

0 голосов
/ 07 мая 2018

Попробуйте это решение. Поправь меня, если я ошибаюсь, но тебе не нужен динамический разворот, если ты знаешь, что хочешь месяцев от 1 до 13.

В первом CTE мы группируем данные по месяцам, затем вычисляем разницу каждого месяца по сравнению с текущим месяцем с помощью DATEDIFF MONTH и, наконец, поворачиваем значения только для разниц месяца от 1 до 13.

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

CREATE TABLE #Data (
    InvoiceDate DATE,
    ItemCode INT,
    Units INT)

INSERT INTO #Data (
    InvoiceDate,
    ItemCode,
    Units)
VALUES
    ('2018-05-07', 123456, 20),
    ('2018-05-04', 123456, 5),
    ('2018-04-07', 123456, 10),
    ('2017-05-25', 123456, 50),
    ('2017-09-07', 123456, 40),
    ('2018-01-07', 123456, 35)

;WITH GroupedMonths AS
(
    SELECT
        ItemCode = D.ItemCode,
        Year = DATEPART(YEAR, D.InvoiceDate),
        Month = DATEPART(MONTH, D.InvoiceDate),
        Units = SUM(D.Units),
        InitialDate = DATEFROMPARTS(
            DATEPART(YEAR, D.InvoiceDate),
            DATEPART(MONTH, D.InvoiceDate),
            1),
        CurrentInitialDate = DATEFROMPARTS(
            DATEPART(YEAR, GETDATE()),
            DATEPART(MONTH, GETDATE()),
            1)
    FROM
        #Data AS D
    GROUP BY
        D.ItemCode,
        DATEPART(YEAR, D.InvoiceDate),
        DATEPART(MONTH, D.InvoiceDate)
),
MonthRankings AS
(
    SELECT
        G.ItemCode,
        G.Units,
        MonthRanking = DATEDIFF(MONTH, G.InitialDate, G.CurrentInitialDate) + 1
    FROM
        GroupedMonths AS G
)
SELECT
    T.ItemCode,
    '01' = ISNULL(T.[1], 0),
    '02' = ISNULL(T.[2], 0),
    '03' = ISNULL(T.[3], 0),
    '04' = ISNULL(T.[4], 0),
    '05' = ISNULL(T.[5], 0),
    '06' = ISNULL(T.[6], 0),
    '07' = ISNULL(T.[7], 0),
    '08' = ISNULL(T.[8], 0),
    '09' = ISNULL(T.[9], 0),
    '10' = ISNULL(T.[10], 0),
    '11' = ISNULL(T.[11], 0),
    '12' = ISNULL(T.[12], 0),
    '13' = ISNULL(T.[13], 0)
FROM
    MonthRankings AS R
    PIVOT (
        MAX(R.Units) FOR R.MonthRanking IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
    ) AS T
...