Sha*_*ars 9 sql postgresql database-design string-concatenation calculated-columns
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)
);
Run Code Online (Sandbox Code Playgroud)
Error: generation expression is not immutable
The goal is to populate the first name and last into the full name column.
Erw*_*ter 10
concat()是 not IMMUTABLE(仅STABLE),因为它可以调用timestamptz_out依赖于语言环境设置的数据类型输出函数(如)。Tom Lane(核心开发人员)在这里解释了它。
而且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
, ...
);
Run Code Online (Sandbox Code Playgroud)
db<>在这里摆弄
该CASE表达式尽可能快 - 比多个串联和函数调用快得多。并且完全正确。
或者,如果您知道自己在做什么并拥有必要的权限,请按照此处所示创建一个IMMUTABLEconcat 函数(以替换CASE表达式):
旁白:full_name需要varchar(101)(50+50+1)才有意义。或者只是使用text列。看:
最佳解决方案取决于您计划如何准确处理 NULL 值(和空字符串)。我可能不会添加生成的列,这通常比即时连接全名更昂贵且更容易出错。考虑一个视图。或者封装精确连接逻辑的函数。
有关的:
这适用于||运算符:
CREATE TABLE person (
person_id smallserial NOT NULL,
first_name character varying(50),
last_name character varying(50),
full_name character varying(100) generated always as (first_name || ' ' || last_name) STORED,
birth_date date,
created_timestamp timestamp default current_timestamp,
PRIMARY KEY (person_id)
);
Run Code Online (Sandbox Code Playgroud)
我不确定为什么concat()被认为是可变的技术原因,但||事实并非如此。
如果你想处理NULL列中的值,那就有点复杂了。我可能会推荐:
trim(both ' ' from
(' ' || coalesce(first_name, '') || ' ' || coalesce(last_name, '')
)
)
Run Code Online (Sandbox Code Playgroud)
当然,这与您的表达式并不完全相同,因为它删除了名称开头和结尾的空格。
| 归档时间: |
|
| 查看次数: |
4432 次 |
| 最近记录: |