with可以解决很多想用子表解决的问题
over可以加想加的,改变表的结构
例题:
表(driver)说明:司机登录登出明细表,由于同一司机有可能同时登录两个司机端,所以同一时间段一个司机有可能会产生两条或者更多条数据。
字段名 描述 类型:
driver_id 司机id bigint
login 登录时间 yyyy-mm-dd HH:MM:SS
exit 下线时间 yyyy-mm-dd HH:MM:SS
题目:请你统计2024年8月1日后的所有司机在线时长,要求对司机时间去重,每个司机在线时长精确到秒。
注:我们保证在8月1日0时做了一次司机清场,即保证不会有司机8月1日之前登录8月1日之后退出的情况出现。
法一:利用lead()加一列有效退出时间
法二:with语句
WITH driver_time AS (
SELECT driver_id, login AS event_time, 1 AS flag
FROM driver
WHERE login >= '2024-08-01'
UNION ALL
SELECT driver_id, exit AS event_time, -1 AS flag
FROM driver
WHERE exit >= '2024-08-01'
-- 给出登录和登出的标志
),
driver_status AS (
SELECT
driver_id,
event_time,
SUM(flag) OVER (PARTITION BY driver_id ORDER BY event_time) AS online_status
FROM driver_time
-- 给出在线状态
),
driver_intervals AS (
SELECT
driver_id,
event_time AS start_time,
LEAD(event_time) OVER (PARTITION BY driver_id ORDER BY event_time) AS end_time,
online_status
FROM driver_status
-- 用了lead()
)
SELECT
driver_id,
SUM(TIMESTAMPDIFF(SECOND, start_time, end_time)) AS total_online_duration_seconds
FROM driver_intervals
WHERE online_status > 0
AND end_time IS NOT NULL
GROUP BY driver_id;
driver_id event_time flag online_status end_time
001 '2024-08-01 07:00:00' 1 1 '2024-08-01 08:00:00'
001 '2024-08-01 08:00:00' 1 2 '2024-08-01 09:00:00'
001 '2024-08-01 09:00:00' -1 1 '2024-08-01 10:00:00'
001 '2024-08-01 10:00:00' -1 0 '2024-08-01 11:00:00'
001 '2024-08-01 11:00:00' 1 1 '2024-08-01 12:00:00'
001 '2024-08-01 12:00:00' -1 0 null