GENERATE_SERIES生成最近7天日期最稳妥方式是CURRENT_DATE为起点、CURRENT_DATE-INTERVAL'6 days'为终点、步长'-1 day'并转::date;按月生成需防月末截断;参数类型须严格匹配;超50万行应加LIMIT或物化表。

GENERATE_SERIES 生成最近7天日期(含今天)
直接用 GENERATE_SERIES 配合 CURRENT_DATE 最稳妥,不用手写7次减法。关键点是把当前日期当作起点,步长设为 -1 day,并控制好上下界:
- 起点用
CURRENT_DATE,终点用CURRENT_DATE - INTERVAL '6 days'(这样共7天:0 到 -6 天) - 步长必须是
INTERVAL类型,写成'-1 day'或INTERVAL '-1 day'都行,但不能漏掉单位 - 结果默认是
timestamp with time zone,加::date转成纯日期更干净
示例:
SELECT GENERATE_SERIES(CURRENT_DATE, CURRENT_DATE - INTERVAL '6 days', '-1 day')::date AS dt ORDER BY dt;
按月生成日期序列时的“月末陷阱”
用 GENERATE_SERIES 按月递增(INTERVAL '1 month')时,起始日如果是 1月31日、3月31日这类“不存在于所有月份”的日期,PostgreSQL 会自动截断到当月最后一天——比如从 '2024-01-31' 开始加一个月,得到的是 '2024-02-29',不是 '2024-03-03'。
- 这不是 bug,是 PostgreSQL 对
interval加法的定义行为 - 如果业务要求“每月固定日”(如每月15号),别用
GENERATE_SERIES直接加月,改用generate_series(1, n) + interval构造再date_trunc('month', ...) + INTERVAL '15 days' - 若真要严格按自然月滚动且保留起始日逻辑,得用 PL/pgSQL 写自定义函数,
GENERATE_SERIES做不到
类型对齐错误:为什么报 “function generate_series(bigint, bigint, integer) does not exist”?
这个错误本质是参数类型不匹配。虽然你传了整数,但 PostgreSQL 会按字面量推断类型:1 是 integer,1::bigint 才是 bigint。而 GENERATE_SERIES 的三个重载签名严格区分 integer/bigint/numeric 和 interval。
- 日期场景下通常用
timestamp版本,所以起点/终点必须是date或timestamp,不能是整数 - 数值场景下,如果表主键是
BIGINT,又想用GENERATE_SERIES补序号,就得显式转类型:GENERATE_SERIES(1::BIGINT, 1000::BIGINT) - 混用类型(比如起点用
date,步长用integer)会直接报错,必须统一为interval
性能边界:百万级序列要不要 LIMIT?
GENERATE_SERIES 在 10 万以内基本无感,但超过 50 万行后,内存占用和计划生成时间会明显上升,尤其在子查询或 JOIN 场景下容易拖慢整个查询。
- 线上报表类 SQL 中,永远显式加
LIMIT,哪怕只是防御性地写LIMIT 100000 - 不要依赖外部 WHERE 过滤来“减少结果”——
GENERATE_SERIES会先全量生成再过滤,开销已发生 - 如果需要超大范围(比如生成 10 年每日日期),优先考虑物化为一张小表,而不是每次查都实时生成
日期序列看着简单,但类型、截断逻辑、性能边界这三点,最容易在上线后突然冒出来。特别是跨月场景,别只测 1月→2月,一定补测 1月31日→2月31日这种 case。










