显示每月出席日期明智

时间:2016-09-22 05:09:25

标签: sql sql-server pivot

我需要使用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

1 个答案:

答案 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查看实际查询。