[英]Why am I getting a an error when creating a generated column in PostgreSQL?
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(核心開發人員)在這里解釋了它。
和first_name || ' ' || last_name
first_name || ' ' || last_name
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<> 在這里擺弄
CASE
表達式盡可能快 - 比多個串聯和函數調用快得多。 並且完全正確。
或者,如果您知道自己在做什么並擁有必要的權限,請創建一個IMMUTABLE
concat 函數,如下所示(替換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)
);
我不確定concat()
被認為是可變的技術原因,但是||
不是。
如果要處理列中的NULL
值,則稍微復雜一些。 我可能會推薦:
trim(both ' ' from
(' ' || coalesce(first_name, '') || ' ' || coalesce(last_name, '')
)
)
當然,這與您的表達式不完全相同,因為它從名稱的開頭和結尾刪除了空格。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.