我有两个表,一个是事件的开始时间,第二个是事件的结束时间,我想加入两个
然而,挑战在于每个开始事件并不总是有相应的结束事件,如果是这样,我希望在输出中为 NULL。这可能吗?
编辑:每个 ID 代表一个人,每天可以有多个事件开始和停止。对于每个事件,我只希望将单个“正确”结束时间连接到开始时间(如果存在)。目前没有单个事件级别的标识符。
例如:
表1:开始时间
id ts_start
123 01:00
123 03:00
123 05:00
123 09:00
表 2:结束时间
id ts_end
123 02:00
123 07:00
输出:
id ts_start ts_end
123 01:00 02:00
123 03:00 NULL
123 05:00 07:00
123 09:00 NULL
我在 MySQL 5.7 上,所以还不能访问窗口/分析功能,尽管如果这是最佳解决方案的一部分,那么我很乐意迁移(尽管必须是开源的,所以新版本的MySQL 或 Postgres)
谢谢
最佳答案
首先你需要得到一个ts_end
的“候选”,它是大于开始时间的最小结束时间。这可以通过
select s.id, s.ts_start, (
select min(e.ts_end)
from end_time e
where e.id = s.id
and e.ts_end > s.ts_start
) as ts_end
from start_time s;
或与
select s.id, s.ts_start, min(e.ts_end) as ts_end
from start_time s
left join end_time e
on e.id = s.id
and e.ts_end > s.ts_start
group by s.id, s.ts_start
两个查询都会返回
| id | ts_start | ts_end |
|-----|----------|----------|
| 123 | 01:00 | 02:00 |
| 123 | 03:00 | 07:00 |
| 123 | 05:00 | 07:00 |
| 123 | 09:00 | null |
现在当 ts_start 之间有任何开始时间(表
和 start_time
)时,我们需要 ts_end
为 null
(第二行) ts_end
。对于第二行 ts_end
必须是 NULL
,因为有一个开始时间 5:00
介于 3:00
和 7:00
。
对于第一个查询,我们可以使用带有 NOT EXISTS
条件的 HAVING
子句:
select s.id, s.ts_start, (
select min(e.ts_end)
from end_time e
where e.id = s.id
and e.ts_end > s.ts_start
having not exists (
select *
from start_time s2
where s2.id = s.id
and s2.ts_start > s.ts_start
and s2.ts_start < min(e.ts_end)
)
) as ts_end
from start_time s
可以使用 CASE
表达式和 EXISTS
条件扩展第二个查询:
select s.id, s.ts_start,
case when exists (
select *
from start_time s2
where s2.id = s.id
and s2.ts_start > s.ts_start
and s2.ts_start < min(e.ts_end)
)
then null
else min(e.ts_end)
end as ts_end
from start_time s
left join end_time e
on e.id = s.id
and e.ts_end > s.ts_start
group by s.id, s.ts_start
在 MySQL 8.x 中,您可以改用 LEAD
窗口函数:
select s.id, s.ts_start,
case when min(e.ts_end) > lead(s.ts_start) over (partition by s.id order by s.ts_start)
then null
else min(e.ts_end)
end as ts_end
from start_time s
left join end_time e
on e.id = s.id
and e.ts_end > s.ts_start
group by s.id, s.ts_start
所有三个查询都将返回:
| id | ts_start | ts_end |
|-----|----------|----------|
| 123 | 01:00 | 02:00 |
| 123 | 03:00 | null |
| 123 | 05:00 | 07:00 |
| 123 | 09:00 | null |
关于mysql - SQL根据第一个表中的时间差连接第二个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51798794/