CASE语句输出不符合预期:无法正确标记跨季度状态变更
问题分析与修复方案
你的问题出在CASE语句的逻辑是基于单条记录的,但状态变化是跨两条记录的判断——每条行只能对应一个year和quarter,所以永远不可能同时满足year=2020 and quarter=4和year=2021 and quarter=1这两个条件,这就是为什么两行的status_change_during_2021_q1都返回0。
要实现跨季度的状态变更判断,你需要用窗口函数来获取同一个id的上一个季度的状态数据,然后在当前记录中做对比。
修复后的SQL
select *, case when year = 2021 and quarter = 1 -- 获取同id的上一条记录的status and lag(status) over (partition by id order by year, quarter) = 'no' and status = 'yes' then 1 else 0 end as status_change_during_2021_q1 from( ... ... ) t order by id, year, quarter limit 50
逻辑解释
lag(status) over (partition by id order by year, quarter):这个窗口函数会按id分组,然后按year和quarter排序,为每条记录取出它的上一条记录的status值。- 当当前记录是2021年第1季度时,我们检查上一个季度的状态是否为
no,同时当前状态是yes,如果满足就标记为1,否则为0。
更严谨的版本(应对缺失季度的情况)
如果你的数据可能存在季度缺失的情况(比如某个id没有2020Q4的记录,直接有2021Q1),可以进一步判断上一条记录的年份和季度,确保我们对比的确实是2020Q4:
select *, case when year = 2021 and quarter = 1 and lag(year) over (partition by id order by year, quarter) = 2020 and lag(quarter) over (partition by id order by year, quarter) = 4 and lag(status) over (partition by id order by year, quarter) = 'no' and status = 'yes' then 1 else 0 end as status_change_during_2021_q1 from( ... ... ) t order by id, year, quarter limit 50
这样执行后,2021Q1的那条记录就会正确返回1了。
内容的提问来源于stack exchange,提问作者cs_guy




