SQL Select陈述一个月的出勤时间

时间:2019-01-25 22:43:02

标签: sql sql-server sql-server-2014

任何人都可以帮忙吗?我们的考勤系统会生成以下数据:

Empid    Department  Timestamp                  Read_ID
3221      IT          2017-01-29 11:12:00.000    1
5565      IT          2017-01-29 12:28:06.000    1
5565      IT          2017-01-29 12:28:07.000    1
3221      IT          2017-01-29 13:12:00.000    2
5565      IT          2017-01-29 13:28:06.000    2
3221      IT          2017-01-30 07:42:15.000    1
3221      IT          2017-01-30 16:16:15.000    2
3221      IT          2017-01-31 09:05:00.000    1
3221      IT          2017-01-31 11:05:00.000    2
3221      IT          2017-01-31 13:20:00.000    1
3221      IT          2017-01-31 16:10:00.000    2

其中Read_ID值为:

  • 1 =条目
  • 2 =退出

我正在寻找要在MS SQL 2014上运行的SQL查询,例如,汇总每个员工每月的出勤时间

Empid   Department  Year    Month   TotalHours
3221    IT          2017    1       15:24
5565    IT          2017    1       01:00

2 个答案:

答案 0 :(得分:2)

此查询应为您提供所需的结果。它的工作方式是选择每个条目,然后将其与同一员工的下一个退出一起加入(忽略没有进一步退出的条目):这为我们提供了该员工轮班的时间。然后汇总结果并在每个组中汇总轮班时间。

SELECT
    t1.empid, 
    t1.department, 
    YEAR(t1.timestamp) Year,
    MONTH(t1.timestamp) Month,
    CONVERT(
        varchar(12), 
        DATEADD(minute, SUM(DATEDIFF(minute, t1.timestamp, t2.timestamp)), 0), 
        114
    ) TotalHours
FROM
    mytable t1
    INNER JOIN mytable t2 
        ON  t1.empid = t2.empid
        AND t2.read_id = 2
        AND t2.timestamp = (
            SELECT MIN(timestamp) 
            FROM mytable 
            WHERE 
                read_id = 2 
                AND empid = t2.empid 
                AND timestamp > t1.timestamp
        )
WHERE 
    t1.read_id = 1 
GROUP BY t1.empid, t1.department, YEAR(t1.timestamp), MONTH(t1.timestamp)
ORDER BY  1, 2, 3, 4

返回:

 empid | department | Year | Month | TotalHours  
 ----: | :--------- | ---: | ----: | :-----------
  3221 | IT         | 2017 |     1 | 15:24:00:000
  5565 | IT         | 2017 |     1 | 02:00:00:000

DB Fiddle demo on SQL Server 2014


但是,在极端情况下,员工输入两次然后存在(这种情况发生在您的数据中,员工556529/01/2017 12:28:06输入,而{em>在输入{1}},然后在29/01/2017 12:28:07退出,上面的查询将考虑两个重叠的条目,并将它们映射到同一出口,导致这一小时的工作被计算两次。

这与您的预期结果相符,但这是您真正想要的吗?这是另一种查询,如果连续出现多个相同的雇员条目,则仅考虑最新的一个:

29/01/2017 13:28:06

返回:

 empid | department | Year | Month | TotalHours  
 ----: | :--------- | ---: | ----: | :-----------
  3221 | IT         | 2017 |     1 | 15:24:00:000
  5565 | IT         | 2017 |     1 | 01:00:00:000

DB fiddle

答案 1 :(得分:1)

尝试一下。我不确定哪种时间格式可以满足您的系统要求,所以我将两者放在同一位置:

SELECT * INTO #Tbl3 FROM (VALUES
(3221,'IT','2017-01-29 11:12:00.000',1),
(5565,'IT','2017-01-29 12:28:06.000',1),
(5565,'IT','2017-01-29 12:28:07.000',1),
(3221,'IT','2017-01-29 13:12:00.000',2),
(5565,'IT','2017-01-29 13:28:06.000',2),
(3221,'IT','2017-01-30 07:42:15.000',1),
(3221,'IT','2017-01-30 16:16:15.000',2),
(3221,'IT','2017-01-31 09:05:00.000',1),
(3221,'IT','2017-01-31 11:05:00.000',2),
(3221,'IT','2017-01-31 13:20:00.000',1),
(3221,'IT','2017-01-31 16:10:00.000',2))
x (Empid,Department,Timestamp,Read_ID)

;With cte as (
    SELECT t1.Empid, t1.Department
        , [Year] = Year(t1.Timestamp)
        , [Month] = Month(t1.Timestamp)
        , Seconds = SUM(DATEDIFF(second, t1.Timestamp, t2.Timestamp))
    FROM #Tbl3 as t1
    OUTER APPLY (
        SELECT Timestamp = MIN(t.Timestamp) 
        FROM #Tbl3 as t
        WHERE t.Department = t1.Department and t.Empid = t1.Empid
            and t.Timestamp > t1.Timestamp and t.Read_ID = 2
    ) as t2
    WHERE t1.Read_ID = 1
    GROUP BY t1.Empid, t1.Department, Year(t1.Timestamp), Month(t1.Timestamp))
SELECT *, TotalHours = Seconds / 3600., TotalTime =
    RIGHT('0'+CAST(Seconds / 3600 as VARCHAR),2) + ':' +
    RIGHT('0'+CAST((Seconds % 3600) / 60 as VARCHAR),2) + ':' +
    RIGHT('0'+CAST(Seconds % 60 as VARCHAR),2)
FROM cte;