2012-02-13 87 views
4

我试图改变这样的数据:PIVOT SQL数据和填写空白

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) 

看到查询在行动here

我试图完成什么?我正朝着正确的方向走吗?任何帮助,将不胜感激!

+1

什么也没有用PIVOT工作? – 2012-02-13 18:17:27

+0

@ subt13,** Me **。我从来没有用过它,我不知道如何“填补空白”。例如,我需要为所有未包含在第一个结果集中的月份显示零。 – 2012-02-13 18:21:30

+0

使用枢轴,就是这么做的。你可以使用isnull(...,0) – 2012-02-13 18:26:48

回答

2

你可以做到这一点没有枢轴(我觉得令人畏惧的语法)。由于事先不知道列的实际布局,我认为这对于动态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个月,如果您需要13个月,则可以将TOP (12)更改为TOP (13),或者如果您不希望包含当前月份,请将其删除-1

+0

你可以用类似的方式用动态SQL建立一个'PIVOT'。您也可以考虑将年份添加到列名中,以便结果明确。最后,输出SQL没有'ORDER BY' - 你的意思是'ORDER BY InvType DESC'还是你不关心命令? – 2012-02-13 18:51:28

+0

完美的作品。我以前从未使用过动态SQL。这是为什么我需要更多地考虑它的一个很好的例子。谢谢你的帮助! – 2012-02-13 19:46:38

2

如果你需要一个动态的支点:see here

否则

这是你怎么做会转动。当然,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 
+0

'month when([date])<5'是什么意思? – 2012-02-13 18:54:46

+0

@AaronBertrand - 添加示例数据。 – 2012-02-13 18:56:36

+0

好的,我陷入了困境。希望OP能够理解这不是解决方案的一部分。现在,其他10-11个月呢? :-) – 2012-02-13 18:58:54