所以我有一个包含这样的时钟信息的SQL表。员工在特定日期工作的分钟数。该表持有数年但却缺少星期六和星期日以及其他非工作日/假期(偶尔例外)。
EmployeeID Date Attended Total Minutes
-----------------------------------
001 '11/01/2011' 319
002 '11/01/2011' 355
003 '11/01/2011' 352
001 '11/02/2011' 340
002 '11/02/2011' 322
003 '11/02/2011' 351
我需要编写一个数据透视表,在报告中显示这样的数据,汇总给定月份的出勤率。
EmployeeId '11/01/2011' '11/02/2011' .... (for all dates in a month)
-----------------------------------------------------------------------
001 319 340
002 355 322
003 352 351
我有一个有效的解决方案(见下文)...... 但我的方法使用动态sql 从给定月份的日期构建数据透视表。在我的脑海里,我一直认为必须有一种不使用动态SQL的方法 - 但它并没有找到我。任何建议...... 我坚持使用动态SQL吗?
DECLARE @columns VARCHAR(8000)
DECLARE @headers VARCHAR(8000)
DECLARE @lowdate Date
DECLARE @highdate Date
SELECT @columns = COALESCE(@columns + ',[' + cast(Attended as varchar) + ']',
'[' + cast(Attended as varchar)+ ']')
FROM TimeAttended WHERE attended >= @date and attended <= @highdate
GROUP BY Attended
SELECT @headers = COALESCE(@Headers + ',Sum([' + cast(Attended as varchar) + ']) as [' + cast(Attended as varchar) + ']',
'Sum([' + cast(Attended as varchar)+ ']) as [' + cast(Attended as varchar) + ']')
FROM TimeAttended WHERE attended >= @date and attended <= @highdate
GROUP BY Attended
DECLARE @query VARCHAR(8000)
SET @query = '
SELECT employeeid, ' + @headers + '
FROM TimeAttended
PIVOT
(
Sum(TotalMinutes)
FOR [Attended]
IN (' + @columns + ')
)
AS p group by employeeid'
EXECUTE(@query)
答案 0 :(得分:1)
除了动态SQL,
如果每一位输出只属于一个月,那么你可以将所有日期的硬编码从1到31:
with data as (
select *
from (
values
(001, '20111101', 319),
(002, '20111101', 355),
(003, '20111101', 352),
(001, '20111102', 340),
(002, '20111102', 322),
(003, '20111102', 351)
) foo (EmployeeID, [Date], [Minutes])
),
prepared_data as (
select EmployeeID, [Minutes], day([date]) as [day]
from data
)
select *
from
prepared_data
pivot (min([Minutes]) for [day] in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],[31])) pvt
;
然后在稍后阶段隐藏或忽略仅有null
s的列。
答案 1 :(得分:1)
除了显而易见的使用动态SQL(我通常希望尽可能避免)之外,还有两个静态选项。
第一种方法是将行正常运行,然后在显示代码中旋转结果(无论你有多少,都会这样做)。这假设您正在生成某种类型的报告,并且具有必要的处理能力。
第二个要求略微区分数据
不是创建语句来查看特定的日期集,而是编写它以查看过去31天的集(从某个给定日期开始)。
也就是说,column2是给定日期,column3是给定日期--1天等等:
SELECT a.Id, COALESCE(b.Minutes, 0), COALESCE(c.Minutes, 0), (etc)
FROM Employees as a
LEFT JOIN TimeClock as b
ON b.EmployeeId = a.id
AND b.Date = @Given
LEFT JOIN TimeClock as c
ON C.EmployeeId = a.Id
AND c.Date = DATEADD(DAY, 1, @Given)
(etc)
...然后将其映射到结果的column1到显示表的column1等等。
答案 2 :(得分:0)
如果您希望列标题基于值,则必须提前知道值,否则必须使用动态SQL。
唯一可以执行此操作的数据库是MS Access'TRANSFORM