使用 PL/pgSQL 循环查询列表或日期范围

Use PL/pgSQL to loop through a query a list or range of dates

我想 运行 以下查询过去 120 个月中的每一个月。这是在 'snapshot' 时间点活跃的记录的简单计数,由打开和关闭日期给出...

select
    date_trunc('month', current_date - interval '1' month) as snapshot_date,
    count(*) as count_active
from table1
where opened_date <= date_trunc('month', current_date - interval '1' month) 
and closed_date > date_trunc('month', current_date - interval '1' month)

我的常规方法是使用 'union',像这样...

select
    date_trunc('month', current_date - interval '1' month) as snapshot_date,
    count(*) as count_active
from table1
where opened_date <= date_trunc('month', current_date - interval '1' month) 
and closed_date > date_trunc('month', current_date - interval '1' month)

union

select
    date_trunc('month', current_date - interval '2' month) as snapshot_date,
    count(*) as count_active
from table1
where opened_date <= date_trunc('month', current_date - interval '2' month) 
and closed_date > date_trunc('month', current_date - interval '2' month)

union

select
    date_trunc('month', current_date - interval '3' month) as snapshot_date,
    count(*) as count_active
from table1
where opened_date <= date_trunc('month', current_date - interval '3' month) 
and closed_date > date_trunc('month', current_date - interval '3' month)
...

但是复制和发布代码,并更改每个日期范围显然是不可行的。如何编写 PL/pgsql 以通过查询循环 list/range 日期和 return 单个输出?

提前致谢

您可以使用 generate series 来实现:

with cte(c) as (
select generate_series(1,120)
)
select
    date_trunc('month', current_date - cte.c* interval '1' month) as snapshot_date,
    count(*) as count_active
from table1, cte
where opened_date <= date_trunc('month', current_date - cte.c * interval '1' month) 
and closed_date > date_trunc('month', current_date - cte.c * interval '1' month)
group by 1

以上查询将 return 仅来自交易发生月份的记录。如果你想要中间的所有月份:

with cte(date_) as (
select generate_series(date_trunc('month', current_date - 120* interval '1' month), date_trunc('month', current_date),interval '1' month) 
)
select cte.date_ "snapshot_date", count(id) "count_active"
from cte left join table1 on opened_date<=date_ and closed_date>date_
group by 1
order by 1

DEMO