如何使时区时间戳 `timestampz` 列可用于计算列的不可变生成表达式?

问题描述 投票:0回答:1

我有名为

timestampz
created
列,我想使用 Postgres 12+ 生成的列来创建月、日和年的生成列。

由于 timestampz 中有一个时区,像

date_part(create, ..)
EXTRACT (month from created)
这样的表达式会失败并出现错误:
ERROR: generation expression is not immutable
.

我尝试转换为时间戳并修复时区,但两者仍然被视为可变生成表达式:

  1. GENERATED ALWAYS AS (date_part('month', created::timestamp))
  2. 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
数据类型转换时与服务器的配置参数有关吗?

postgresql immutability calculated-columns generated-columns
1个回答
0
投票

为什么这个有效,而不是上面的#2?

#1 和 #2 都不起作用,因为从

timestamptz
timestamp
的转换不是一成不变的。这取决于当前的
time_zone
设置。出于显而易见的原因,生成的列仅接受不可变表达式。

另一方面,

date_part('month', created AT TIME ZONE 'UTC
是不可变的。导出 UTC 时间(或任何给定时区偏移的本地时间)始终会产生相同的结果。

不幸的是,数据类型的名称

timestamp with time zone

 有点误导。根本不存储给定的时区。它只是作为输入修饰符来计算 UTC 时间,该时间存储在内部。参见:

  • 数据类型“timestamp with time zone”中的时区存储
© www.soinside.com 2019 - 2024. All rights reserved.