按ID筛选记录:有Value=b则取b,否则取最新日期记录
解决按Persid筛选记录:优先取Value=b,无则取最新日期的记录
这个需求用窗口函数就能很优雅地解决,比你之前尝试的GROUP BY统计方法更直接高效。先给你看最终的SQL代码,再一步步拆解逻辑:
示例数据与预期结果
先把你的示例数据整理成清晰格式:
原表(假设表名为your_table):
Persid | Value | Date 1 | a | 2023-01-01 1 | a | 2023-01-02 1 | a | 2023-01-03 2 | b | 2023-01-01 2 | a | 2023-01-02 2 | a | 2023-01-03
预期结果:
Persid | Value | Date 1 | a | 2023-01-03 2 | b | 2023-01-01
最优解决方案:使用ROW_NUMBER()窗口函数
WITH ranked_records AS ( SELECT Persid, Value, Date, -- 给每个Persid的记录排序:优先Value=b的,再按日期倒序 ROW_NUMBER() OVER ( PARTITION BY Persid ORDER BY CASE WHEN Value = 'b' THEN 0 ELSE 1 END, Date DESC ) AS rn FROM your_table ) SELECT Persid, Value, Date FROM ranked_records WHERE rn = 1;
代码逻辑拆解
- CTE
ranked_records:给每条记录添加一个行号rn,按Persid分组(也就是每个Persid单独处理)。 - 排序规则:
- 用
CASE表达式给Value='b'的记录标记为0,其他为1——这样所有'b'的记录会排在同组最前面(因为0<1)。 - 对于没有'b'的组,按
Date降序排列,最新的日期会自动排在第一位。
- 用
- 筛选结果:取每个组里
rn=1的记录,就是我们要的目标——要么是该Persid任意一条'b'的记录,要么是最新日期的记录。
替代方案(沿用GROUP BY统计思路)
如果你想继续用之前GROUP BY统计的思路,也可以先找出所有存在'b'的Persid,再分别取数:
WITH has_b_persids AS ( -- 找出所有包含Value=b的Persid SELECT DISTINCT Persid FROM your_table WHERE Value = 'b' ) -- 取有b的Persid的任意一条b记录 SELECT Persid, Value, MIN(Date) AS Date -- 用MIN/MAX都可以,仅为取任意一条 FROM your_table WHERE Persid IN (SELECT Persid FROM has_b_persids) AND Value = 'b' GROUP BY Persid, Value UNION ALL -- 取没有b的Persid的最新日期记录 SELECT t.Persid, t.Value, t.Date FROM your_table t LEFT JOIN has_b_persids h ON t.Persid = h.Persid WHERE h.Persid IS NULL QUALIFY ROW_NUMBER() OVER (PARTITION BY t.Persid ORDER BY t.Date DESC) = 1;
不过这个方法需要两次查询再合并,效率不如第一种窗口函数方案,推荐优先用第一种。
内容的提问来源于stack exchange,提问作者Aadam
相关产品推荐
相关产品推荐

