This is 不可能用一个简单的DEFAULT
值,如手册明确指出 https://www.postgresql.org/docs/current/sql-createtable.html:
该值是任何无变量表达式(子查询和
不允许交叉引用当前表中的其他列)。
你可以使用trigger https://www.postgresql.org/docs/current/sql-createtrigger.html反而:
CREATE OR REPLACE FUNCTION trg_foo_b_default()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
-- For just a few constant options, CASE does the job:
NEW.b := CASE NEW.a
WHEN 'peter' THEN 'doctor'
WHEN 'weirdo' THEN 'shrink'
WHEN 'django' THEN 'undertaker'
-- ELSE null default
END;
/*
-- For more, or dynamic options, consider a lookup table:
SELECT INTO NEW.b t.b
FROM def_tbl t
WHERE t.a = NEW.a;
*/
RETURN NEW;
END
$func$;
CREATE TRIGGER b_default
BEFORE INSERT ON foo
FOR EACH ROW
WHEN (NEW.b IS NULL AND NEW.a IS NOT NULL)
EXECUTE FUNCTION trg_foo_b_default();
对于 Postgres 10 或更早版本,请使用EXECUTE PROCEDURE ...
反而。看:
- 触发功能不存在,但我很确定它存在 https://dba.stackexchange.com/a/255319/3684
为了使其更有效,请使用WHEN
触发器定义中的子句(自 Postgres 9.0 起可用)。这样,触发器函数仅在实际有用时才执行。 (假设我们可以让b IS NULL
滑动如果a IS NULL
.)
在 Postgres 12 或更高版本中,GENERATED
列可能是更好的解决方案。看jian的补充答案 https://stackoverflow.com/a/69569932/939860。但请注意,这些限制手册 https://www.postgresql.org/docs/current/sql-createtable.html:
生成表达式可以引用表中的其他列,但是
不是其他生成的列。使用的任何函数和运算符都必须是
不可变的。不允许引用其他表。
这个触发器是与a略有不同DEFAULT
value在那个空值中b
总是被替换为派生的值a
,同时一个DEFAULT
只是默认值,可以通过任何显式输入来推翻。
A GENERATED
列不允许开始输入。