SQL实现:为含Class=A的学生生成符合规则的FLAG字段
问题:完善SQL实现学生FLAG字段计算
原表结构与数据
TABLE1表包含STUDENT、TIME、CLASS三个字段,数据如下:
| STUDENT | TIME | CLASS |
|---|---|---|
| 1 | 1 | D |
| 1 | 2 | A |
| 1 | 3 | B |
| 1 | 4 | C |
| 1 | 5 | A |
| 2 | 1 | C |
| 2 | 2 | A |
| 2 | 3 | A |
| 2 | 4 | C |
| 3 | 1 | A |
| 4 | 1 | F |
| 4 | 2 | C |
| 5 | 1 | C |
| 5 | 1 | A |
| 6 | 1 | A |
| 6 | 1 | C |
需求说明
筛选所有存在CLASS='A'记录的学生,为这些学生的每一行数据添加FLAG字段,规则如下:
- 若该学生对应
CLASS='A'的最小TIME值小于其对应CLASS='C'的最小TIME值,或该学生无CLASS='C'记录,则FLAG=1 - 否则
FLAG=0
现有问题SQL
以下代码无法实现需求:
SELECT *, CASE WHEN MIN(TIME WHERE CLASS = 'A') < MIN(TIME WHERE CLASS = 'C') THEN 1 ELSE 0 as FLAG FROM TABLE1 WHERE CLASS = 'A'
问题分析
原SQL存在几个核心问题:
WHERE CLASS='A'会过滤掉学生的非A类记录,无法保留该学生的所有行数据MIN(TIME WHERE CLASS = 'A')不是标准SQL语法,条件聚合需用CASE嵌套实现- 未按
STUDENT分组,计算的是全局最小时间而非每个学生的分组最小时间 - 未处理学生无
CLASS='C'记录的场景,漏掉了FLAG=1的判定条件
修正后的SQL实现
方式一:使用窗口函数(推荐,保留原表顺序)
SELECT t1.*, CASE WHEN MIN(CASE WHEN CLASS = 'A' THEN TIME END) OVER (PARTITION BY STUDENT) < MIN(CASE WHEN CLASS = 'C' THEN TIME END) OVER (PARTITION BY STUDENT) OR MIN(CASE WHEN CLASS = 'C' THEN TIME END) OVER (PARTITION BY STUDENT) IS NULL THEN 1 ELSE 0 END AS FLAG FROM TABLE1 t1 WHERE STUDENT IN (SELECT DISTINCT STUDENT FROM TABLE1 WHERE CLASS = 'A') ORDER BY t1.STUDENT, t1.TIME, t1.CLASS;
方式二:使用CTE预计算FLAG(适合大数据量场景)
WITH student_flag_info AS ( SELECT STUDENT, CASE WHEN MIN(CASE WHEN CLASS = 'A' THEN TIME END) < MIN(CASE WHEN CLASS = 'C' THEN TIME END) OR MIN(CASE WHEN CLASS = 'C' THEN TIME END) IS NULL THEN 1 ELSE 0 END AS FLAG FROM TABLE1 WHERE CLASS IN ('A', 'C') GROUP BY STUDENT HAVING MIN(CASE WHEN CLASS = 'A' THEN TIME END) IS NOT NULL -- 确保只保留有A记录的学生 ) SELECT t1.*, sfi.FLAG FROM TABLE1 t1 JOIN student_flag_info sfi ON t1.STUDENT = sfi.STUDENT ORDER BY t1.STUDENT, t1.TIME, t1.CLASS;
代码说明
- 筛选目标学生:通过子查询或CTE的
HAVING条件,确保只保留存在CLASS='A'记录的学生 - 分组计算最小时间:用
CASE嵌套聚合函数,按学生分组分别计算A类和C类的最小TIME - FLAG判定:同时覆盖两种
FLAG=1的场景——A的最小时间更早,或无C类记录;其余情况FLAG=0
内容的提问来源于stack exchange,提问作者bvowe
相关产品推荐
相关产品推荐

