SQL Server 2008 R2中考勤矩阵的SQL查询

SQL Server 2008 R2中考勤矩阵的SQL查询,sql,sql-server,tsql,sql-server-2008-r2,Sql,Sql Server,Tsql,Sql Server 2008 R2,我想根据员工输入和输出生成一个矩阵考勤报告,这两个字段都是日期时间字段和按日期分组 通常我会这样计算 请找到附件 请在这方面帮助我这里有一点小技巧,基本上使用递归CTE来获取时间组,然后通过PIVOT生成所需的输出 ;WITH cte (groupNo, StartTime, EndTime) AS ( SELECT CAST(1 AS INT) as groupNo, CAST('06:00' AS TIME) AS StartTime, CAST('07:00' AS TIME) A

我想根据员工输入和输出生成一个矩阵考勤报告,这两个字段都是日期时间字段和按日期分组

通常我会这样计算

请找到附件


请在这方面帮助我

这里有一点小技巧,基本上使用递归CTE来获取时间组,然后通过PIVOT生成所需的输出

;WITH cte (groupNo, StartTime, EndTime)
AS (
    SELECT CAST(1 AS INT) as groupNo, CAST('06:00' AS TIME) AS StartTime, CAST('07:00' AS TIME) AS EndTime
    UNION ALL
    SELECT groupNo + 1 AS groupNo, DATEADD(HOUR, 1, StartTime) AS StartTime, DATEADD(HOUR, 1, EndTime) AS EndTime
    FROM cte
    WHERE groupNo <= 13
)
SELECT emp_id, date_in, date_out, 
       COUNT(DISTINCT datetime_in) AS [NumberOfLogins], 
       SUM(ISNULL([1],0) + ISNULL([2],0) + ISNULL([3],0) + ISNULL([4],0) + ISNULL([5],0) + ISNULL([6],0) + ISNULL([7],0) + ISNULL([8],0) + ISNULL([9],0) + ISNULL([10],0) + ISNULL([11],0) + ISNULL([12],0) + ISNULL([13],0)) [Minutes], 
       SUM([1]) [6AM to 7AM], 
       SUM([2]) [7AM to 8AM], 
       SUM([3]) [8AM to 9AM], 
       SUM([4]) [9AM to 100AM], 
       SUM([5]) [10AM to 11AM], 
       SUM([6]) [11AM to 12PM], 
       SUM([7]) [12PM to 1PM], 
       SUM([8]) [1PM to 2PM], 
       SUM([9]) [2PM to 3PM], 
       SUM([10]) [3PM to 4PM], 
       SUM([11]) [4PM to 5PM], 
       SUM([12]) [5PM to 6PM], 
       SUM([13]) [6PM to 7PM]
FROM 
(
SELECT emp_id, date_in AS datetime_in, CAST(date_in AS DATE) AS date_in, CAST(date_out AS DATE) AS date_out, cte.groupNo, 
        DATEDIFF(MINUTE, (CASE WHEN CAST(t.date_in AS TIME) > cte.StartTime THEN CAST(t.date_in AS TIME) ELSE cte.StartTime END), 
                    (CASE WHEN cte.EndTime > CAST(t.date_out AS TIME) THEN CAST(t.date_out AS TIME) ELSE cte.EndTime END)) AS [minutes]
FROM scan_station_master t
INNER JOIN cte ON (cte.StartTime BETWEEN CAST(t.date_in as time) AND CAST(t.date_out AS TIME)) 
OR (cte.EndTime BETWEEN CAST(t.date_in AS TIME) AND CAST(t.date_out as time))
OR (CAST(t.date_in as time) >= cte.StartTime AND CAST(t.date_out as time) <= cte.EndTime)
) d
PIVOT
    (
      MAX([minutes])
      FOR groupNo in ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13])
    ) piv
GROUP BY emp_id, date_in, date_out

查看并尝试其他样本数据。将讨论t'row

declare @t table(emp_id bigint,date_in datetime,date_out datetime)
insert into @t values
(392510,'2017/2/16 9:47','2017/2/16 11:31'),
(392510,'2017/2/17 11:26','2017/2/17 11:58')
,(392510,'2017/2/17 2:11 PM','2017/2/17 4:13 PM')
,(392510,'2017/2/18 15:30','2017/2/18 17:09')
,(392510,'2017/2/22 9:38 AM','2017/2/22 9:48 AM')
,(392510,'2017/2/22 11:55 AM','2017/2/22 12:10 PM')
,(392510,'2017/2/25 8:20 AM','2017/2/25 8:24 AM')
,(392510,'2017/2/26 13:37','2017/2/26 13:55')

;with CTE as
(

select t.emp_id
,t.date_in
,t.date_out
,case 
when  cast(date_in as time)>cast('7:00 AM' as time) and cast(date_in as time)>cast('6:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('7:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('7:00 AM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('7:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('7:00 AM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('7:00 AM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('7:00 AM' as time)) between 0 and 60
then datediff(MINUTE, cast('6:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('6:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[6 AM to 7 AM]
,case 
when  cast(date_in as time)>cast('8:00 AM' as time) and cast(date_in as time)>cast('7:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('8:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('8:00 AM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('8:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('8:00 AM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('8:00 AM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('8:00 AM' as time)) between 0 and 60
then datediff(MINUTE, cast('7:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('7:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[7 AM to 8 AM]
,case 
when  cast(date_in as time)>cast('9:00 AM' as time) and cast(date_in as time)>cast('8:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('9:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('9:00 AM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('9:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('9:00 AM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('9:00 AM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('9:00 AM' as time)) between 0 and 60
then datediff(MINUTE, cast('8:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('8:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[8 AM to 9 AM]
,case 
when  cast(date_in as time)>cast('10:00 AM' as time) and cast(date_in as time)>cast('9:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('10:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('10:00 AM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('10:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('10:00 AM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('10:00 AM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('10:00 AM' as time)) between 0 and 60
then datediff(MINUTE, cast('9:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('9:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[9 AM to 10 AM]
,case 
when  cast(date_in as time)>cast('11:00 AM' as time) and cast(date_in as time)>cast('10:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('11:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('11:00 AM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('11:00 AM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('11:00 AM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('11:00 AM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('11:00 AM' as time)) between 0 and 60
then datediff(MINUTE, cast('10:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('10:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[10 AM to 11 AM]
,case 
when  cast(date_in as time)>cast('12:00 PM' as time) and cast(date_in as time)>cast('11:00 AM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('12:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('12:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('12:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('12:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('12:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('12:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('11:00 AM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('11:00 AM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[11 AM to 12 PM]
,case 
when  cast(date_in as time)>cast('1:00 PM' as time) and cast(date_in as time)>cast('12:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('1:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('1:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('1:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('1:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('1:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('1:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('12:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('12:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[12 PM to 1 PM]   
,case 
when  cast(date_in as time)>cast('2:00 PM' as time) and cast(date_in as time)>cast('1:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('2:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('2:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('2:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('2:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('2:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('2:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('1:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('1:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[1 PM to 2 PM]    
,case 
when  cast(date_in as time)>cast('3:00 PM' as time) and cast(date_in as time)>cast('2:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('3:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('3:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('3:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('3:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('3:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('3:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('2:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('2:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[2 PM to 3 PM]
,case 
when  cast(date_in as time)>cast('4:00 PM' as time) and cast(date_in as time)>cast('3:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('4:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('4:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('4:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('4:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('4:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('4:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('3:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('3:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[3 PM to 4 PM]
,case 
when  cast(date_in as time)>cast('5:00 PM' as time) and cast(date_in as time)>cast('4:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('5:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('5:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('5:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('5:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('5:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('5:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('4:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('4:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[4 PM to 5 PM]
,case 
when  cast(date_in as time)>cast('6:00 PM' as time) and cast(date_in as time)>cast('5:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('6:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('6:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('6:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('6:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('6:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('6:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('5:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('5:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[5 PM to 6 PM]
,case 
when  cast(date_in as time)>cast('7:00 PM' as time) and cast(date_in as time)>cast('6:00 PM' as time) then  null
when  datediff(MINUTE, cast(date_in as time) ,cast('7:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('7:00 PM' as time)) between 0 and 60 
then  datediff(MINUTE, cast(date_in as time) ,cast(date_out as time))
when  datediff(MINUTE, cast(date_in as time) ,cast('7:00 PM' as time)) <60 
and datediff(MINUTE, cast(date_out as time) ,cast('7:00 PM' as time)) <0
then datediff(MINUTE, cast(date_in as time) ,cast('7:00 PM' as time))
when  datediff(MINUTE, cast(date_out as time) ,cast('7:00 PM' as time)) between 0 and 60
then datediff(MINUTE, cast('6:00 PM' as time),cast(date_out as time) )
when  datediff(MINUTE, cast('6:00 PM' as time) ,cast(date_out as time))>=60 
then 60
else
null
end 
[6 PM to 7 PM]
From @t t
)
select emp_id,min(date_in)date_in,max(date_out)date_out
,count(*)[Number of Login]
,sum([6 AM to 7 AM])[6 AM to 7 AM]
,sum([7 AM to 8 AM])[7 AM to 8 AM]
,sum([8 AM to 9 AM])[8 AM to 9 AM]
,sum([9 AM to 10 AM])[9 AM to 10 AM]
,sum([10 AM to 11 AM])[10 AM to 11 AM]
,sum([10 AM to 11 AM])[10 AM to 11 AM]
,sum([11 AM to 12 PM])[11 AM to 12 PM]
,sum([12 PM to 1 PM]  )[12 PM to 1 PM]  
,sum([1 PM to 2 PM])[1 PM to 2 PM]
,sum([2 PM to 3 PM])[2 PM to 3 PM]
,sum([3 PM to 4 PM])[3 PM to 4 PM]
,sum([4 PM to 5 PM])[4 PM to 5 PM]
,sum([5 PM to 6 PM])[5 PM to 6 PM]
,sum([6 PM to 7 PM])[6 PM to 7 PM]
from CTE t
group by t.emp_id,cast(date_in as date)

请阅读一些关于改进您的问题的提示。感谢Stephen的出色努力。只是我替换了我的表扫描站主数据,我的标准字段是emp\u id、date\u in和date\u out。但我发现下面的语法错误。Msg 102,15级,状态1,第1行“,”附近的语法不正确。Msg 102,级别15,状态1,第32行“>”附近的语法不正确。此处显示语法错误>:IIFCASTt.date\u in AS TIME>cte.StartTime,请编辑我的数据库引擎支持的查询。我使用的是SQLServer2008R2I,很抱歉,当我用您的查询进行测试时,它运行良好并得到了结果。但我把我真正的桌子搞砸了。你能用我的真实表格和真实字段编辑吗。表:扫描站点主字段:emp\U id、输入日期、输出日期再次发送查询。哇!它起作用了。非常感谢你的努力。这是一个很好的问题。谢谢你的帮助。但我正在努力使用真实表运行相同的查询。结果显示为空。我的表格是scan_station_master,数据字段是emp_id、date_in、date_out。这个版本也可以正常工作。非常感谢你的帮助。