SQL关联表无过滤统计:各Training Type下全时段晚于今日的Session数
SQL统计需求:计算每个Training Type下所有Slot均晚于今日的Training Session数量
需求说明
- 数据层级:Training Type包含多个Training Session,每个Training Session包含多个Slot,Slot有
start日期字段 - 目标:统计每个Training Type下,所有Slot的start时间都晚于今日的Training Session总数
- 核心限制:不能使用WHERE子句,否则会丢失像Training Type 3这类无符合条件Session的记录
- 此前问题:之前的方法误统计了关联后的总行数,尝试CASE方法时不确定
MIN(date)的有效性
示例数据
Training Type表
| training_type_id | name |
|---|---|
| 1 | 基础培训 |
| 2 | 进阶培训 |
| 3 | 已结束培训 |
Training Session表
| session_id | training_type_id |
|---|---|
| 101 | 1 |
| 102 | 1 |
| 201 | 2 |
| 301 | 3 |
Slot表(假设今日为2024-09-28)
| slot_id | session_id | start_date |
|---|---|---|
| 1 | 101 | 2024-10-01 |
| 2 | 101 | 2024-10-02 |
| 3 | 102 | 2024-09-25 |
| 4 | 201 | 2024-10-05 |
| 5 | 301 | 2024-09-20 |
预期输出
| training_type_id | name | valid_session_count |
|---|---|---|
| 1 | 基础培训 | 1 |
| 2 | 进阶培训 | 1 |
| 3 | 已结束培训 | 0 |
正确SQL实现
SELECT tt.training_type_id, tt.name, COUNT(CASE WHEN s.min_start > CURRENT_DATE THEN ts.session_id END) AS valid_session_count FROM training_type tt LEFT JOIN training_session ts ON tt.training_type_id = ts.training_type_id LEFT JOIN ( SELECT session_id, MIN(start_date) AS min_start FROM slot GROUP BY session_id ) s ON ts.session_id = s.session_id GROUP BY tt.training_type_id, tt.name;
方案解释
- 子查询
s先按session_id分组,算出每个Session最早的Slot开始时间min_start——毕竟如果一个Session里最早的Slot都在今日之后,那它所有Slot肯定都符合要求 - 全程用
LEFT JOIN关联三张表,确保所有Training Type的记录都被保留,完全规避了WHERE子句过滤数据的问题 - 外层用
COUNT(CASE...)统计:只有当Session的最早Slot时间晚于今日时,才计入该Session,COUNT会自动忽略NULL值,刚好得到符合条件的Session数量
内容的提问来源于stack exchange,提问作者nook
相关产品推荐
相关产品推荐

