我正在建立一个新的SQL查询,以汇总员工出勤表中的记录。这些记录是从指纹或RFID传感器下载的,并记录在同一张表上。我想得到工作时间。
如果员工每天进出工作场所一次,一切都很好。设备在表上生成2条记录,这不是问题。轻松确定出入时间。
但是我不知道如何解决此人是否进来,休息一下(离开工作场所),然后他再次进来直到退出时间。
假定它们在每个时间间隔上始终都是偶数记录(到达和退出时间戳记)。另外,员工从不检查一天,而在第二天离开。
我有以下查询。请记住:这只会获得最小时间戳(到达时间)和最大时间戳(离开时间)。
SELECT Userid, Name, Date, Entrance, Exit, Hours FROM
(SELECT Userid AS user,
CONVERT(VARCHAR, CONVERT(TIME, min(Checktime))) AS Entrance,
CONVERT(VARCHAR, CONVERT(TIME, max(Checktime))) AS Exit,
CONVERT(VARCHAR, CONVERT(TIME, max(Checktime)-min(CheckTime))) AS Hours,
CONVERT(VARCHAR, CONVERT(DATE, CheckTime)) AS Fecha,
COUNT(*) AS Regs,
SUM(edited) AS edited FROM attendance
WHERE CONVERT(DATE, CheckTime) < CONVERT(DATE, GETDATE())
GROUP BY Userid, CONVERT(DATE, CheckTime)) AS Hs
INNER JOIN Userinfo
ON Userinfo.Userid = Hs.user
ORDER BY Date DESC, Name ASC;
例如,如果表具有以下记录:
id | Logid | Userid | CheckTime | edited
1 | 10 | 1 | 2019-06-18 8:00:00 | 0
2 | 11 | 1 | 2019-06-18 12:00:00 | 0
3 | 12 | 1 | 2019-06-18 15:00:00 | 0
4 | 13 | 1 | 2019-06-18 17:00:00 | 0
5 | 14 | 2 | 2019-06-18 8:00:00 | 0
6 | 15 | 2 | 2019-06-18 17:00:00 | 0
我得到的是
Userid | Name | Date | Entrance | Exit | Hours | edited
1 | Gandalf | 2019-06-18 | 8:00:00 | 17:00:00 | 9:00:00 | 0
2 | Frodo | 2019-06-18 | 8:00:00 | 17:00:00 | 9:00:00 | 0
我需要什么:
Userid | Name | Date | Entrance | Exit | Hours | edited
1 | Gandalf | 2019-06-18 | 8:00:00 | 17:00:00 | 6:00:00 | 0
2 | Frodo | 2019-06-18 | 8:00:00 | 17:00:00 | 9:00:00 | 0
总时间由(12:00:00-8:00:00)+(17:00:00-15:00:00)计算得出。 在这种情况下,“入口”和“退出”列根本没有必要。
您知道我该如何解决吗?非常感谢你!
答案 0 :(得分:2)
这假设您有一对输入/退出并处理多个中断。
with cte as (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [Userid], cast ([CheckTime] as Date)
ORDER BY [CheckTime]) as rn
FROM Table1 t1
)
SELECT c1.[Userid],
cast (c1.[CheckTime] as Date) as the_day,
SUM (DATEDIFF (hh, c1.[CheckTime], c2.[CheckTime])) as total_hours
FROM cte c1
JOIN cte c2
ON c1.rn = c2.rn -1
AND c1.[Userid] = c2.[Userid]
AND c1.rn % 2 = 1
GROUP BY c1.[Userid],
cast (c1.[CheckTime] as Date) ;
输出
| Userid | the_day | total_hours |
|--------|------------|-------------|
| 1 | 2019-06-18 | 6 |
| 2 | 2019-06-18 | 9 |
注意:
DATEDIFF的常规语法:
DATEDIFF(datepart, start_date, end_date)
只需实现函数DATEDIFF即可计算两个日期值之间的时间间隔,并将其作为整数返回。
因此,如果您使用hh
作为日期部分的08:00和09:30,您仍然会获得1h。也许最好使用mi
除以60
答案 1 :(得分:0)
完美! Juan Carlos的解决方案效果很好!
我之所以发布此帖子,是因为我已经编辑了他的一些代码以符合最初的发布要求。
代码完全相同。只有我更改/添加了几行
package example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AccountTester implements Runnable {
private Account account;
private double amount;
public AccountTester(Account account, double amount) {
this.account = account;
this.amount = amount;
}
public static void main(String[] args) {
Account account = new Account(0);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new AccountTester(account, 1.0));
executorService.execute(new AccountTester(account, 2.0));
executorService.shutdown();
System.out.println("End balance: " + account.getBalance());
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
account.deposit(amount);
}
}
}
此查询返回:
with cte as (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [Userid], cast ([CheckTime] as Date)
ORDER BY [CheckTime]) as rn
FROM Table1 t1
WHERE CAST(CheckTime AS DATE) = '2019-06-17' -- Filter by specific date
)
SELECT c1.[Userid],
cast (c1.[CheckTime] as Date) as the_day,
-- Return time as HH:MM
CONVERT(VARCHAR, SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/3600) + ':' + right('00' + CONVERT(VARCHAR, CONVERT(FLOAT, (SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/60) - ((SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/3600)*60))),2) as total_time
FROM cte c1
JOIN cte c2
ON c1.rn = c2.rn -1
AND c1.[Userid] = c2.[Userid]
AND c1.rn % 2 = 1
GROUP BY c1.[Userid],
cast (c1.[CheckTime] as Date);