DB:SQL Server 2005
我们有一个以这种方式拥有数据的表:
Project Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
-------------------- ----------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
11-11079 2008 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 75244.90
11-11079 2009 466.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
11-11079 2010 855.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
01-11052 2009 56131.00 0.00 36962.00 -61596.00 2428.00 84.00 0.00 0.00 0.00 0.00 0.00 0.00
有人希望数据显示为整个项目的一行。这些列将是动态的,取决于它未来多少年。一个例子是:
Project Jan-2009 Feb-2009 Mar-2009 Apr-2009... Dec-2009 Jan-2010
-------------- ------------ ------------ ------------ ----------- ------------ ---------
11-11079 466.00 0.00 0.00 0.00 0.00 855.00
01-11052 56131.00 0.00 36962.00 -61596.00 2428.00 0.00
我读过许多例子,其中日期在每个条目的一列中填充,但我没有发现任何情况,其中月份是列名称,年份在行中。
带有数据透视表的动态SQL? 或者使用SQL,临时表,联接和联合进行一些相当大规模的操作? 有关使用SSIS数据透视表功能的任何想法吗?
答案 0 :(得分:4)
您的数据已经过调整,但需要在不同的级别进行调整。我认为处理此问题的最佳方法是先将其取消,然后再处理正确的枢轴级别。
第1步:取消透视
您可以使用SQL 2005 UNPIVOT命令,或使用CROSS JOIN技术。以下是两者的示例。注意我在中间省了几个月以保持简单。只需添加它们即可。
-- CROSS JOIN method (also works in SQL 2000)
SELECT
P.Project,
Mo =
DateAdd(mm,
X.MonthNum,
DateAdd(yy, P.[Year] - 1900, '19000101')
),
Amount =
CASE X.MonthNum
WHEN 0 THEN Jan
WHEN 1 THEN Feb
WHEN 11 THEN Dec
END
FROM
ProjectData P
CROSS JOIN (
SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 11
) X (MonthNum)
每一行重复12次,然后CASE语句每行只抽出一个月,这样就可以很好地忽略数据。
-- UNPIVOT method
SELECT
P.Project,
Mo =
DateAdd(mm,
Convert(int, P.MonthNum),
DateAdd(yy, P.[Year] - 1900, '19000101')
),
P.Amount
FROM
(
SELECT Project, [Year], [0] = Jan, [1] = Feb, [11] = Dec
FROM ProjectData
) X UNPIVOT (Amount FOR MonthNum IN ([0], [1], [11])) P
DROP TABLE ProjectData
这两种方法都不是一个明显的表现赢家。有时一个比另一个好(取决于被转动的数据)。 UNPIVOT方法在CROSS JOIN不执行的执行计划中使用过滤器。
第2步:再次转发
现在,如何使用不透明的数据。您没有说明某人将如何使用此功能,但由于您需要将数据放入某种类型的输出文件中,我建议使用SSRS(Sql Server Reporting Services),附带SQL Server 2005,无需额外费用。
只需使用Matrix报表对象来转移上述其中一个查询即可。此对象可以很好地确定在报表运行时生成列标签的数据值,并且听起来就像您需要的那样。如果添加一个按照您喜欢的方式格式化日期的列,则可以按Mo列排序,但使用新表达式作为列标签。
SSRS还提供各种格式和日程安排选项。例如,您可以通过电子邮件发送Excel文件或将网页保存到文件共享。
如果我遗漏了任何东西,请告诉我。
对于任何想要查看上述代码的人,这里有一些创建脚本:
USE tempdb
CREATE TABLE ProjectData (
Project varchar(10),
[Year] int,
Jan decimal(15, 2),
Feb decimal(15, 2),
Dec decimal(15, 2)
)
SET NOCOUNT ON
INSERT ProjectData VALUES ('11-11079', 2008, 0.0, 0.0, 75244.90)
INSERT ProjectData VALUES ('11-11079', 2009, 466.0, 0.0, 0.0)
INSERT ProjectData VALUES ('11-11079', 2010, 855.0, 0.0, 0.0)
INSERT ProjectData VALUES ('01-11052', 2009, 56131.0, 0.0, 0.0)
答案 1 :(得分:0)
我编写了一个名为 pivot_query 的存储过程,可以帮助解决这个问题,来源是here,示例包含原始数据here。
With your data:
create table ProjectData
(
Project varchar(20),
[Year] Integer,
Jan decimal(12,2),
Feb decimal(12,2),
Mar decimal(12,2),
Apr decimal(12,2),
May decimal(12,2),
Jun decimal(12,2),
Jul decimal(12,2),
Aug decimal(12,2),
Sep decimal(12,2),
Oct decimal(12,2),
Nov decimal(12,2),
Dec decimal(12,2)
);
insert into ProjectData values ('11-11079',2008, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 75244.90);
insert into ProjectData values ('11-11079',2009, 466.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00);
insert into ProjectData values ('11-11079',2010, 855.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00) ;
insert into ProjectData values ('01-11052',2009, 56131.00, 0.00, 36962.00, -61596.00, 2428.00, 84.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00);
declare @mySQL varchar(MAX)
set @mySQL = 'select * from ProjectData'
exec pivot_query @mySQL, 'Project', 'Year', 'max(Jan) Jan,max(Feb) Feb,max(Mar) Mar,max(Apr) Apr,max(Jun) Jun,max(Jul) Jul,max(Aug) Aug,max(Sep) Sep,max(Oct) Oct,max(Nov) Nov,max(Dec) Dec'
Results:
Project 2008_Jan 2008_Feb 2008_Mar 2008_Apr 2008_Jun 2008_Jul 2008_Aug 2008_Sep 2008_Oct 2008_Nov 2008_Dec 2009_Jan 2009_Feb 2009_Mar 2009_Apr 2009_Jun 2009_Jul 2009_Aug 2009_Sep 2009_Oct 2009_Nov 2009_Dec 2010_Jan 2010_Feb 2010_Mar 2010_Apr 2010_Jun 2010_Jul 2010_Aug 2010_Sep 2010_Oct 2010_Nov 2010_Dec
-------------------- ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------
01-11052 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 56131.00 .00 36962.00 -61596.00 84.00 .00 .00 .00 .00 .00 .00 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
11-11079 .00 .00 .00 .00 .00 .00 .00 .00 .00 .00 75244.90 466.00 .00 .00 .00 .00 .00 .00 .00 .00 .00 .00 855.00 .00 .00 .00 .00 .00 .00 .00 .00 .00 .00
不是完全但非常接近。 : - )
答案 2 :(得分:-1)
我认为你可以使用嵌套的while循环和一些动态SQL来实现。如果您无法保存最终表格,或者您必须每月重新生成所有列,这将是一个缓慢的解决方案。但是,如果它只是添加剂,那么它可能并不坏。无论如何,我就是这样做的: