如何用单条SQL查询按指定规则筛选表中符合要求的行?
问题需求
原始数据表
| Column_A | Column_B | Column_C |
|---|---|---|
| 1 | UserA | NULL |
| 2 | UserB | NULL |
| 3 | UserC | 1 |
| 4 | UserA | 1 |
| 5 | UserB | NULL |
| 6 | UserB | 2 |
| 7 | UserC | 2 |
需要返回包含Column_A、Column_B、Column_C字段,且满足以下任一条件的所有行:
- Column_C取值为NULL
- 对于Column_C的每一个非NULL唯一值,优先返回Column_B等于UserA的第一行;若不存在此类行,则返回按Column_B关联的time_created字段排序后的第一行
预期输出结果
| Column_A | Column_B (FK) | Column_C |
|---|---|---|
| 1 | UserA | NULL |
| 2 | UserB | NULL |
| 4 | UserA | 1 |
| 5 | UserB | NULL |
| 6 | UserB | 2 |
实现方案
问题分析
原有SQL存在两个核心问题:
- GROUP BY粒度设置错误,同时按Column_C和唯一值字段Column_A分组,最终每组只有1行,自然无法实现按Column_C分组去重的效果
- 字符串常量
UserA未加单引号,会被SQL解析器识别为字段名,本身就会运行报错
我们可以通过窗口函数ROW_NUMBER()实现自定义优先级取行的需求,单条查询即可完成逻辑。
正确SQL实现
假设和Column_B关联的time_created字段已经存在于当前表,或者已经通过关联用户表获取,实现代码如下:
WITH ranked_data AS ( SELECT Column_A, Column_B, Column_C, -- 仅对Column_C非NULL的行按值分组排序 ROW_NUMBER() OVER ( PARTITION BY Column_C ORDER BY CASE WHEN Column_B = 'UserA' THEN 1 ELSE 2 END ASC, -- UserA行优先级最高 time_created ASC -- 无UserA行时按创建时间取最早的第一条 ) AS rn FROM your_table_name -- 替换为实际表名 WHERE Column_B IN ('UserA', 'UserB', 'UserC') ) SELECT Column_A, Column_B, Column_C FROM ranked_data WHERE Column_C IS NULL -- 无条件保留所有Column_C为NULL的行 OR rn = 1 -- 非NULL的Column_C每组仅取优先级最高的第一行 ORDER BY Column_C NULLS FIRST, Column_A ASC;
如果time_created存储在Column_B关联的用户表中,只需要修改CTE的FROM部分关联用户表即可:
FROM your_table_name t LEFT JOIN user_table u ON t.Column_B = u.user_name -- 替换为实际关联逻辑
内容的提问来源于stack exchange,提问作者polestar
相关产品推荐
相关产品推荐

