So I have a SQL table that contains time-clock information like this. The number of minutes an employee was at work on a given date. The table holds several years worth of but is missing Saturdays and Sundays and other non work days/holidays (with occasional exceptions).
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
I need to write a pivot that will show the data like this in a report that summarizes attendance to a given month.
EmployeeId '11/01/2011' '11/02/2011' .... (for all dates in a month)
-----------------------------------------------------------------------
001 319 340
002 355 322
003 352 351
I have a solution that works (see below)… but my approach uses dynamic sql to build the pivot statement from the days in a given month. In the back of my mind I keep thinking there has to be a way that does not use dynamic SQL – but it’s not coming to me. Any suggestions… am I stuck with Dynamic 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)
Besides the obvious one of using dynamic SQL (which I generally prefer to avoid if possible), there are two static options.
The first is to get the rows as normal, and then pivoting the results in your display code (which you’re somewhat doing regardless). This is assuming you’re generating a report of some sort, and have the requisite processing power avaliable.
The second requires thinking about the data slightly differently.
Instead of creating the statement to look at a specific set of dates, code it to look at the set of the last 31 days (from some given date).
That is, column2 is the given date, column3 is the given date – 1 day, etc:
… And then mapping it to column1 of the results to column1 of the display table, etc.