题目描述

(通过次数329 | 提交次数587,通过率56.05%)

表: Employees
+--------------+------+
| Column Name  | Type |
+--------------+------+
| employee_id  | int  |
| needed_hours | int  |
+--------------+------+
employee_id 是该表的主键。
每一行都包含员工的 id 和他们获得工资所需的最低工作时数。
表: Logs
+-------------+----------+
| Column Name | Type     |
+-------------+----------+
| employee_id | int      |
| in_time     | datetime |
| out_time    | datetime |
+-------------+----------+
(employee_id, in_time, out_time) 是该表的主键。
该表的每一行都显示了员工的时间戳。in_time 是员工开始工作的时间,out_time 是员工结束工作的时间。
所有时间都在 2022 年 10 月。out_time 可以是 in_time 之后的一天,这意味着该员工在午夜之后工作。
在公司里,每个员工每个月必须工作一定的小时数。员工在工作段中工作。员工工作的小时数可以通过员工在所有工作段中工作的分钟数的总和来计算。每个工作段的分钟数是四舍五入的。
例如,如果员工在一个时间段中工作了 51 分 2 秒,我们就认为它是 52 分钟。
编写一个 SQL 查询来报告将被开除的员工的 id。换句话说,报告没有工作所需时间的员工的 id。
以 任意顺序 返回结果表。

查询结果格式如下所示。
示例 1:
输入: 
Employees 表:
+-------------+--------------+
| employee_id | needed_hours |
+-------------+--------------+
| 1           | 20           |
| 2           | 12           |
| 3           | 2            |
+-------------+--------------+
Logs 表:
+-------------+---------------------+---------------------+
| employee_id | in_time             | out_time            |
+-------------+---------------------+---------------------+
| 1           | 2022-10-01 09:00:00 | 2022-10-01 17:00:00 |
| 1           | 2022-10-06 09:05:04 | 2022-10-06 17:09:03 |
| 1           | 2022-10-12 23:00:00 | 2022-10-13 03:00:01 |
| 2           | 2022-10-29 12:00:00 | 2022-10-29 23:58:58 |
+-------------+---------------------+---------------------+
输出: 
+-------------+
| employee_id |
+-------------+
| 2           |
| 3           |
+-------------+
解释: 
员工 1:
 - 参加了三个工作段:
    - 在 2022-10-01, 他工作了 8 个小时。
    - 在 2022-10-06, 他工作了 8 小时 4 分钟。
    - 在 2022-10-12, 他工作了 4 小时 1 分钟。请注意,他一直工作到午夜。
 - 员工 1 在各个时段总共工作了 20 小时5分钟,不被开除。
员工 2:
 - 参加了一个工作段:
    - 在 2022-10-29, 他工作了 11 小时 59 分钟。
 - 员工 2 没有工作足够的时长,将被开除。
员工 3:
 - 没有任何工作段。
 - 员工 3 没有工作足够的时长,将被开除。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/employees-with-deductions

//测试数据
Create table If Not Exists Employees (employee_id int, needed_hours int);
Create table If Not Exists Logs (employee_id int, in_time datetime, out_time datetime);

insert into Employees (employee_id, needed_hours) values ('1', '20');
insert into Employees (employee_id, needed_hours) values ('2', '12');
insert into Employees (employee_id, needed_hours) values ('3', '2');

insert into Logs (employee_id, in_time, out_time) values ('1', '2022-10-01 09:00:00', '2022-10-01 17:00:00');
insert into Logs (employee_id, in_time, out_time) values ('1', '2022-10-06 09:05:04', '2022-10-06 17:09:03');
insert into Logs (employee_id, in_time, out_time) values ('1', '2022-10-12 23:00:00', '2022-10-13 03:00:01');
insert into Logs (employee_id, in_time, out_time) values ('2', '2022-10-29 12:00:00', '2022-10-29 23:58:58');

解题思路

Employees表保存了所有的员工及需要的最低工作小时数。
Logs表保存了员工的工作日志。包括每段工作的开始工作时间、结束工作时间。
题目要求:开除那些没有达到最低工作小时数的员工。
首先,需要查询出每个员工的工作小时数。可以从Logs表汇总计算得出。
因为Logs表中只保存了每段工作的开始工作时间和结束工作时间,所以需要使用函数计算出每段工作时间经过的分钟数。对于MySQL数据库来说,可以使用系统自带的timestampdiff函数实现。
然后,与每个员工需要的最低工作小时数比较。未达标的员工,即为需要开除的员工。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
with
tmp as (
    select
        employee_id,
        sum(ceiling(timestampdiff(SECOND,in_time,out_time)/60)) work_minute
    from Logs
    group by employee_id
)
select
    a.employee_id
from Employees a
left join tmp b
on a.employee_id = b.employee_id
where a.needed_hours * 60 > coalesce(b.work_minute,0);
picture loss