我正在尝试转换这些数据:
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。
我正在努力实现的目标是什么?我正朝着正确的方向前进吗?任何帮助将不胜感激!
答案 0 :(得分: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
包括当前月份。
答案 1 :(得分: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