You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写SQL查询获取2018-2020年有预订但2021年无预订的客户

SQL查询实现:筛选2018-2020年有预订、2021年无预订的客户

需求定义

输出2018年至2020年期间有过预订、但2021年没有任何预订的客户报表

现有基础代码(按年份拆分的活跃客户CTE)

你已经编写的按年份拆分年度活跃客户的CTE可以直接复用:

with active_2018 as
(
    select c.id, c.email, c.telephone                       
    from customer c                     
    join booking b on b.customer_id = c.id                      
    where to_char(b.date_created, 'YYYY') = '2018'                      
    group by 1, 2, 3                   
),      
active_2019 as 
(
    select c.id, c.email, c.telephone                       
    from customer c                     
    join booking b on b.customer_id = c.id                      
    where to_char(b.date_created, 'YYYY') = '2019'                      
    group by 1, 2, 3                   
),  
active_2020 as 
(
    select c.id, c.email, c.telephone                       
    from customer c                     
    join booking b on b.customer_id = c.id                      
    where to_char(b.date_created, 'YYYY') = '2020'                      
    group by 1, 2, 3                   
),
active_2021 as 
(
    select c.id, c.email, c.telephone                       
    from customer c                     
    join booking b on b.customer_id = c.id                      
    where to_char(b.date_created, 'YYYY') = '2021'                      
    group by 1, 2, 3                   
)

原有错误写法问题说明

你首次尝试的写法用inner join关联三个年度的活跃客户表,只有同时在2018、2019、2020三年都有预订的客户才会被关联保留,不符合「任意一年有预订即可」的要求。

正确实现方案

方案1:基于现有CTE直接修改

用UNION合并2018-2020三年的活跃客户,再排除2021年有预订的客户即可:

select id, email, telephone
from (
    select id, email, telephone from active_2018
    union
    select id, email, telephone from active_2019
    union
    select id, email, telephone from active_2020
) active_2018to2020
where id not in (select id from active_2021)
  • UNION会自动对合并的客户数据去重,不需要额外加distinct
  • 逻辑和需求完全匹配:只要2018-2020任意一年有预订,且2021年无预订就会被保留

方案2:更简洁的优化写法(无需拆分多个CTE)

如果不需要单独保留各年度的CTE,可直接一次聚合统计,性能更优:

select c.id, c.email, c.telephone
from customer c
join booking b on b.customer_id = c.id
group by c.id, c.email, c.telephone
having 
    -- 判断2018-2020至少有1笔预订
    max(case when to_char(b.date_created, 'YYYY') between '2018' and '2020' then 1 else 0 end) = 1
    -- 判断2021年无任何预订
    and max(case when to_char(b.date_created, 'YYYY') = '2021' then 1 else 0 end) = 0

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:27:01