要生成一系列日期,这是最佳方式:
SELECT t.day::date
FROM generate_series(timestamp '2004-03-07'
, timestamp '2004-08-16'
, interval '1 day') AS t(day);
等效的,不太明确的简短语法:
SELECT day::date
FROM generate_series(timestamp '2004-03-07', '2004-08-16', '1 day') day;
或者使用列表中的 set-returning 函数SELECT
:
SELECT generate_series(timestamp '2004-03-07', '2004-08-16', '1 day')::date AS day;
在最后一个变体中需要AS
关键字,否则 Postgres 会误解列别名。而且我不建议在 Postgres 10 之前使用该变体 - 至少在同一个列表中没有一个以上的 set-returning 函数:day
SELECT
(除此之外,最后一个变体通常以微弱的优势最快。)
为什么timestamp [without time zone]
?
有许多重载的generate_series()
. 目前(Postgres 11):
SELECT oid::regprocedure AS function_signature
, prorettype::regtype AS return_type
FROM pg_proc
where proname = 'generate_series';
函数签名 | 返回类型
:------------------------------------------------ ------------------------------------------- | :----------------------------
generate_series(整数,整数,整数) | 整数
生成系列(整数,整数)| 整数
生成系列(大整数,大整数,大整数) | 大整数
生成系列(大整数,大整数) | 大整数
generate_series(数字,数字,数字) | 数字
生成系列(数字,数字)| 数字
generate_series(时间戳不带时区,时间戳不带时区,间隔) | 没有时区的时间戳
generate_series(timestamp with time zone,timestamp with time zone,interval) | 带时区的时间戳
(numeric
Postgres 9.5 添加了变体。)相关的是最后两个以粗体取和返回timestamp
/ timestamptz
。
没有变体采取或返回date
。需要显式强制转换才能返回date
。带timestamp
参数的调用直接解析为最佳变体,而无需下降到函数类型解析规则,也无需对输入进行额外的强制转换。
timestamp '2004-03-07'
是完全有效的,顺便说一句。省略的时间部分默认为00:00
ISO 格式。
感谢函数类型解析,我们仍然可以通过date
. 但这需要 Postgres 做更多的工作。有一个隐式转换from date
totimestamp
和一个 from date
to timestamptz
。会模棱两可,但在“日期/时间类型”中timestamptz
是“首选”。所以比赛是在步骤4d 决定的。:
遍历所有候选对象并将那些接受首选类型(输入数据类型的类型类别)的候选对象保留在需要类型转换的大多数位置。如果没有人接受首选类型,则保留所有候选人。如果只剩下一个候选人,请使用它;否则继续下一步。
除了函数类型解析中的额外工作之外,这还增加了额外的强制转换timestamptz
——这不仅增加了成本,而且还可能引入 DST 问题,在极少数情况下导致意外结果。(DST 是一个愚蠢的概念,顺便说一句,不能强调这一点。)相关:
我在小提琴中添加了演示,显示了更昂贵的查询计划:
db<>在这里摆弄
有关的: