CREATE TABLE my_app.person
(
person_id smallserial NOT NULL,
first_name character varying(50),
last_name character varying(50),
full_name character varying(100) generated always as (concat(first_name, ' ', last_name)) STORED,
birth_date date,
created_timestamp timestamp default current_timestamp,
PRIMARY KEY (person_id)
);
错误:生成表达式不是一成不变的
目的是填充名字,最后填充到全名列中。
最佳答案
concat()
不是IMMUTABLE
(仅STABLE
),因为它可以调用依赖于语言环境设置的数据类型输出函数(例如timestamptz_out
)。 Tom Lane (core developer) explains it here.
并且first_name || ' ' || last_name
等于,而不是等效于concat(first_name, ' ', last_name)
,而至少一列可以是NULL
。
详细说明:
解决方案
要使其正常工作,请按照您演示的方式进行:
CREATE TABLE person (
person_id smallserial PRIMARY KEY
, first_name varchar(50)
, last_name varchar(50)
, full_name varchar(101) GENERATED ALWAYS AS
(CASE WHEN first_name IS NULL THEN last_name
WHEN last_name IS NULL THEN first_name
ELSE first_name || ' ' || last_name END) STORED
, ...
);
db <> fiddle here
CASE
表达式的速度与所获得的一样快-远快于多个串联和函数调用。完全正确。或,如果您知道自己在做什么,并具有必要的特权,则创建一个
IMMUTABLE
concat函数,如此处所示(替换CASE
表达式):另外:
full_name
必须为varchar(101)
(50 + 50 + 1)才有意义。或仅使用text
列即可。看:一般建议
最佳解决方案取决于您计划如何精确地处理NULL值(和空字符串)。我可能不会添加生成的列,这通常比在运行时串联全名通常更昂贵且总体上容易出错。考虑一个 View 。或封装了精确串联逻辑的函数。
有关的:
关于sql - 为什么在PostgreSQL中创建生成的列时出现错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60249404/