我需要为每个月的每个人在我的桌子中的每个人之间为每个月创建一个行(结果应是一个月的第一天)。例如,如果我的源表中有以下数据:
rowID | person | startdate | enddate
1 | 12345 | 2014-04-01 | 2014-11-30
2 | 67890 | 2014-03-01 | 2014-05-01
我希望目标表中的结果为:
person | month
12345 | 2014-04-01
12345 | 2014-05-01
12345 | 2014-06-01
12345 | 2014-07-01
12345 | 2014-08-01
12345 | 2014-09-01
12345 | 2014-10-01
12345 | 2014-11-01
67890 | 2014-03-01
67890 | 2014-04-01
67890 | 2014-05-01
非常感谢您的帮助。
不需要CTE或横向加入:
select
person,
generate_series(
date_trunc('month', startdate),
enddate, '1 month'
)::date as month
from rfem
order by 1, 2
;
person | month
--------+------------
12345 | 2014-04-01
12345 | 2014-05-01
12345 | 2014-06-01
12345 | 2014-07-01
12345 | 2014-08-01
12345 | 2014-09-01
12345 | 2014-10-01
12345 | 2014-11-01
67890 | 2014-03-01
67890 | 2014-04-01
67890 | 2014-05-01
计算每个人的最小日期和最大日期,然后使用 generate_series
之间的每月基于每月的范围:
WITH date_ranges AS (
SELECT
person,
min(date_trunc('month', startdate))::timestamptz AS min_start,
max(date_trunc('month', enddate))::timestamptz AS max_end
FROM person_table
GROUP BY 1
)
SELECT
dr.person,
ser.month::DATE as month
FROM date_ranges AS dr,
generate_series(min_start, max_end, '1 month') AS ser(month)
输出
person | month
--------+------------
12345 | 2014-04-01
12345 | 2014-05-01
12345 | 2014-06-01
12345 | 2014-07-01
12345 | 2014-08-01
12345 | 2014-09-01
12345 | 2014-10-01
12345 | 2014-11-01
67890 | 2014-03-01
67890 | 2014-04-01
67890 | 2014-05-01
它如何工作?函数呼叫的隐式 LATERAL JOIN
迫使输入的每行计算。
该解决方案考虑到每个人的日期可能会有1行以上,并且可能是最高的范围。