PIVOT SQL-данные и заполнение пробелов - PullRequest
4 голосов
/ 13 февраля 2012

Я пытаюсь преобразовать эти данные:

ItemID  MonthAsInt  Month     Year  InvType     Quantity
4643    4           April     2011  Shipment    10
4643    5           May       2011  Shipment    10
4643    7           July      2011  Shipment    10
4643    8           August    2011  Destroy     10
4643    11          November  2011  Shipment    25
4643    12          December  2011  Picking     1

В это (в основном, снимок на 12 месяцев):

              February    March    April     May    June    July    August    ...

Shipment      0           0        10        10     0       10      0
Picking       0           0        0         0      0       0       0
Destroy       ...

Я перепутал с PIVIOT метод, но мне не очень повезло.На данный момент все, что у меня есть, это список дат, которые мне нужны между GETDATE() и GETDATE() - 12 months (получено с помощью запроса ниже):

DECLARE @BeginDate DATETIME
DECLARE @EndDate DATETIME

SET @BeginDate = GETDATE();
SET @EndDate = DATEADD(MONTH, -12, GETDATE());

WITH CTE_DatesTable
AS
(
    SELECT @EndDate AS [Date]

    UNION ALL

    SELECT  DATEADD(dd, 1, [date])
    FROM    CTE_DatesTable
    WHERE   DATEADD(dd, 1, [date]) <= @BeginDate
)

SELECT DISTINCT DATENAME(MONTH, [date]) + ' ' 
        + CAST(YEAR([date]) AS VARCHAR(4)) AS MonthYear,
                YEAR([date]) AS YearAsInt,
                MONTH([Date]) AS MonthAsInt
FROM            CTE_DatesTable
ORDER BY        YEAR([date]), MONTH([Date])
OPTION          (MAXRECURSION 0)

См. Запрос в действии здесь .

Возможно ли то, что я пытаюсь достичь?Я иду в правильном направлении?Любая помощь будет оценена!

Ответы [ 2 ]

2 голосов
/ 13 февраля 2012

Если вам нужен динамический круг: см. Здесь

в противном случае

Вот как вы это сделаете, это повернется. Конечно, PIVOT требует, чтобы вы заранее знали, как будут выглядеть ваши данные. Если вам нужен динамический свод, то есть много динамических перекрестных / сводных запросов / sps, которые люди уже написали.

DECLARE @BeginDate DATETIME
DECLARE @EndDate DATETIME

SET @BeginDate = GETDATE();
SET @EndDate = DATEADD(MONTH, -12, GETDATE());

WITH CTE_DatesTable
AS
(
    SELECT @EndDate AS [Date]

    UNION ALL

    SELECT  DATEADD(dd, 1, [date])
    FROM    CTE_DatesTable
    WHERE   DATEADD(dd, 1, [date]) <= @BeginDate
)

    SELECT DISTINCT DATENAME(MONTH, [date]) + ' ' + CAST(YEAR([date]) AS VARCHAR(4)) AS MonthYear,
                    YEAR([date]) AS YearAsInt,
                    MONTH([Date]) AS MonthAsInt,
                    case when month([date]) < 5 then 'Shipment' else 'Picking' end InvType,
                    floor(10 * RAND() * month([date])) Quantity
    into #orig
    FROM            CTE_DatesTable
    ORDER BY        YEAR([date]), MONTH([Date])
    OPTION          (MAXRECURSION 0)

update #orig 
set Quantity = null
where MonthYear = 'February 2011'

select * from #orig

select *
from
(
    select isnull(Quantity, 0) Quantity, MonthYear from #orig
) SourceTbl
PIVOT
(
    sum(Quantity)
    for MonthYear in ([February 2011], [March 2011])
) PivotTbl

drop table #orig

Результат:

February 2011   March 2011
0                   29
2 голосов
/ 13 февраля 2012

Вы можете сделать это без поворота (синтаксис, который я нахожу пугающим также).Поскольку вы заранее не знаете фактическое расположение столбцов, я думаю, что это проще всего с динамическим SQL.Для следующей таблицы / примера данных:

USE tempdb;
GO

CREATE TABLE dbo.foo
(
    ItemID INT, 
    MonthAsInt INT, 
    [Month] VARCHAR(12), 
    [Year] INT, 
    InvType VARCHAR(12), 
    Quantity INT
);

INSERT dbo.foo SELECT 4643,4 ,'April   ',2011,'Shipment',10
UNION ALL SELECT 4643,5 ,'May     ',2011,'Shipment',10
UNION ALL SELECT 4643,7 ,'July    ',2011,'Shipment',10
UNION ALL SELECT 4643,8 ,'August  ',2011,'Destroy ',10
UNION ALL SELECT 4643,11,'November',2011,'Shipment',25
UNION ALL SELECT 4643,12,'December',2011,'Picking ',1;

Вы можете сгенерировать список месяцев, используя гораздо более простой CTE, и построить на его основе динамический оператор SQL:

DECLARE @sql NVARCHAR(MAX) = N'';

;WITH n AS 
(
    SELECT TOP (12) d = DATEADD
    (
        MONTH, 
        -(ROW_NUMBER() OVER (ORDER BY [object_id]) - 1), 
        GETDATE()
    )
    FROM sys.objects
    ORDER BY d DESC
)
SELECT @sql = @sql + N',' + CHAR(13) + CHAR(10) + DATENAME(MONTH, d) 
    + ' = SUM(CASE WHEN [Year] = ' + CONVERT(VARCHAR(4), DATEPART(YEAR, d))
    + ' AND MonthAsInt = ' + CONVERT(VARCHAR(2), DATEPART(MONTH, d)) 
    + ' THEN Quantity ELSE 0 END)'
FROM n
ORDER BY d;

SELECT @sql = N'SELECT InvType' + @sql + '
    FROM dbo.foo
    GROUP BY InvType';

PRINT @sql;
-- EXEC sp_executesql @sql;

Я положил PRINT, чтобы вы могли проверить его перед запуском.Я не был уверен, что вам нужно 12 месяцев или 13 месяцев, вы можете просто изменить TOP (12) на TOP (13), если хотите 13 месяцев, или удалить -1, если вы не хотите, чтобы текущий месяц был включен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...