我需要使用PIVOT以月度格式显示考勤数据。但无法弄清楚应该怎么做。
以下是我的表结构
出勤:
AttendanceID EmployeeID AttendanceDateTime
员工:
EmployeeID EmployeeName
假日:
HolidayID HolidayDate
离开:
LeaveID EmployeeID LeaveDateTime IsApproved
我想从上表
中提供的数据中显示如下结果EmployeeName 01-09-2016 02-09-2016 03-09-2016 04-09-2016
A Present Absent Holiday Leave
答案 0 :(得分:2)
因此,在日期创建数据透视表之前,您可能想要做的第一件事就是确定要转动的日期。出于示例的目的,我刚刚提供了一种方法,您可以在此答案中获得某个范围内的每个日期,但这实际上取决于您要查找的内容。
SELECT *
FROM (
SELECT E.EmployeeID, E.EmployeeName, T.DateToCheck, COALESCE(H.val, A.val, L.val, 'Absent') val
FROM tblEmployee E
CROSS JOIN (
SELECT CAST(DATEADD(DAY, number, '2016-09-01') AS DATE)
FROM master..spt_values
WHERE type = 'P'
AND number <= 3) T(DateToCheck)
LEFT JOIN (SELECT 'Holiday' val, HolidayDate FROM tblHoliday) H ON H.HolidayDate = T.DateToCheck
LEFT JOIN (SELECT 'Present' val, AttendanceDateTime, EmployeeID FROM tblAttendance) A ON CAST(A.AttendanceDateTime AS DATE) = T.DateToCheck AND A.EmployeeID = E.EmployeeID
LEFT JOIN (SELECT 'Leave' val, LeaveDateTime, EmployeeID FROM tblLeave) L ON CAST(L.LeaveDateTime AS DATE) = T.DateToCheck AND L.EmployeeID = E.EmployeeID) T
PIVOT (MAX(val) FOR DateToCheck IN ([2016-09-01], [2016-09-02], [2016-09-03], [2016-09-04])) P;
这里的基本逻辑是你要生成要检查的日期,将这些日期与每个不同的表进行比较(使用左连接或外部应用),只获得一个结果(此答案中的逻辑使用合并到决定它将显示哪个值,然后转动结果。
编辑:如果您需要PIVOT
表示动态的列名称集(例如动态日期范围),则需要使用动态SQL。这是你可以做到的一种方式:
DECLARE @SQL VARCHAR(MAX) = '', @dateRange VARCHAR(MAX) = '', @startDate DATE = '2016-09-01', @endDate DATE = '2016-09-05';
SELECT @dateRange += ',' + QUOTENAME(DATEADD(DAY, number, @startDate))
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number, @startDate) <= @endDate;
SELECT @dateRange = STUFF(@dateRange, 1, 1, '');
SELECT @SQL = 'SELECT *
FROM (
SELECT E.EmployeeID, E.EmployeeName, T.DateToCheck, COALESCE(H.val, A.val, L.val, ''Absent'') val
FROM tblEmployee E
CROSS JOIN (
SELECT CAST(DATEADD(DAY, number, ''' + CAST(@startDate AS CHAR(10)) + ''') AS DATE)
FROM master..spt_values
WHERE type = ''P''
AND DATEADD(DAY, number, ''' + CAST(@startDate AS CHAR(10)) + ''') <= ''' + CAST(@endDate AS CHAR(10)) + ''') T(DateToCheck)
LEFT JOIN (SELECT ''Holiday'' val, HolidayDate FROM tblHoliday) H ON H.HolidayDate = T.DateToCheck
LEFT JOIN (SELECT ''Present'' val, AttendanceDateTime, EmployeeID FROM tblAttendance) A ON CAST(A.AttendanceDateTime AS DATE) = T.DateToCheck AND A.EmployeeID = E.EmployeeID
LEFT JOIN (SELECT ''Leave'' val, LeaveDateTime, EmployeeID FROM tblLeave) L ON CAST(L.LeaveDateTime AS DATE) = T.DateToCheck AND L.EmployeeID = E.EmployeeID) T
PIVOT (MAX(val) FOR DateToCheck IN (' + @dateRange + ')) P;';
PRINT @SQL;
EXEC(@SQL);
更改开始日期和结束日期将更改输出。您可以使用PRINT @SQL
查看实际查询。