用于计算不同客户状态的滚动 Windows 函数

Rolling Windows function for count distinct customer state

我正在尝试计算过去 3 个月、6 个月内不同的客户状态。

我有 customer_idcustomer_status(活跃与否)和 calendar_date。因此,每个客户都可以随着时间的推移多次出现,因为它可以在不同的时间活跃或不活跃。

但是当我尝试下面的代码时它不起作用,因为 windows 函数

不支持 count(distinct)
select *,
count(distinct customer_status)
    over(partition by customer_id
        order by date_trunc ('month',calendar_date) rows between 2 PRECEDING and current row)

from customer_details

我可以在同一个月获得不同的状态[见下文]但我想为 count(distinct) 3 个月和 6 个月创建两个字段。

select calendar_date,
           date_trunc ('month',calendar_date) as calendar_month,
           customer_id,
           customer_status,
    
    count(distinct customer_status)
        over(partition by customer_id, calendar_month))
    
    from customer_details
    order by calendar_date 

有人可以支持我吗?

最后的 select 应该有以下列:

calendar_date [already exist]
calendar_month [already exist]
customer_status [already exist]
count_distinct_status_3month [new]
count_distinct_status_6months [new]

我想使用 windows 函数

这没有直接的功能,而是需要使用自连接。例如,在您的情况下,查询将是这样的。

select cust.calendar_date, date_trunc('month', cust.calendar_date) as calendar_month,
cust.customer_id, count(distinct cust_3mon.customer_status) as count_distinct_status_3month,
count(distinct cust_6mon.customer_status) as count_distinct_status_6month
from customer_details as cust
left join customer_details as cust_3mon
on cust.customer_id=cust_3mon.customer_id
and (date_trunc('month', cust.calendar_date)-date_trunc('month', cust_3mon.calendar_date)) between interval '0 months' and interval '3 months'
left join customer_details as cust_6mon
on cust.customer_id=cust_6mon.customer_id
and (date_trunc('month', cust.calendar_date)-date_trunc('month', cust_6mon.calendar_date)) between interval '0 months' and interval '6 months'
group by 1,2,3
order by 3,2

sqlfiddle link here

我不认为你可以用 window 函数来做到这一点。您可以使用横向连接来做到这一点:

select cd.*, cd2.*
from customer_details cd cross join lateral
     (select count(distinct cd2.customer_status) as cnt1,
             count(distinct case when cd2.calendar_date > cd.calendar_date - interval '3 month' then cd2.customer_status end) as cnt2,
             count(distinct case when cd2.calendar_date > cd.calendar_date - interval '6 month' then cd2.customer_status end) as cnt3
      from customer_details cd2
      where cd2.customer_id = cd.customer_id
     ) cd2