我有名为
timestampz
的 created
列,我想使用 Postgres 12+ 生成的列来创建月、日和年的生成列。
由于 timestampz 中有一个时区,像
date_part(create, ..)
和 EXTRACT (month from created)
这样的表达式会失败并出现错误: ERROR: generation expression is not immutable
.
我尝试转换为时间戳并修复时区,但两者仍然被视为可变生成表达式:
GENERATED ALWAYS AS (date_part('month', created::timestamp))
GENERATED ALWAYS AS (date_part('month', created::timestamp AT TIME ZONE 'UTC'))
但是,正如Erwin Brandstetter在他对这个答案的评论中所指出的,这是有效的:
ALTER TABLE tbl
ADD COLUMN created_year numeric GENERATED ALWAYS AS
(date_part('month', created AT TIME ZONE 'UTC')) STORED;
当然
EXTRACT(month from created AT TIME ZONE 'UTC'))
也可以。
这让我得出这样的结论:如果我想要 N 个时区,我需要 N 个生成的列。 为什么这个有效,而不是上面的#2?
::timestamp
数据类型转换时与服务器的配置参数有关吗?
为什么这个有效,而不是上面的#2?
#1 和 #2 都不起作用,因为从
timestamptz
到 timestamp
的转换不是一成不变的。这取决于当前的 time_zone
设置。出于显而易见的原因,生成的列仅接受不可变表达式。
另一方面,
date_part('month', created AT TIME ZONE 'UTC
是不可变的。导出 UTC 时间(或任何给定时区偏移的本地时间)始终会产生相同的结果。
不幸的是,数据类型的名称 timestamp with time zone
有点误导。根本不存储给定的时区。它只是作为输入修饰符来计算 UTC 时间,该时间存储在内部。参见: