如果我有一列说任何给定值的
column a
,并且我希望另一列column b
根据default value
的值有一个
column a
换句话说:
如果
column a = 'peter'
那么column b default value = 'doctor'
.
这是不可能一个简单的
DEFAULT
值,因为手册明确指出:
值为任意无变量表达式(子查询和 不允许交叉引用当前表中的其他列)。
您可以改用触发器:
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 ...
。参见:
为了使其更有效,请在触发器定义中使用
WHEN
子句(自 Postgres 9.0 起可用)。这样触发函数只有在真正有用的时候才会执行。 (假设如果b IS NULL
我们可以让a IS NULL
滑动。)
在 Postgres 12 或更高版本中,
GENERATED
列可能是更好的解决方案。见jian的补充答案。但是请注意,手册中的这些限制:
生成表达式可以引用表中的其他列,但是 不是其他生成的列。使用的任何函数和运算符必须 不可变的。不允许引用其他表。
这个触发器与DEFAULT
值有细微的不同,因为
b
中的null总是被替换为从
a
派生的值,而
DEFAULT
只是默认值,可以用任何显式输入来否决.
GENERATED
列不允许输入以开头。
生成的列。
https://www.postgresql.org/docs/12/ddl-generated-columns.html
例子:
create temp table foo (
a text,
b text GENERATED ALWAYS AS (
case WHEN a = 'telegram' THEN 'im'
WHEN a = 'proton' THEN 'email'
WHEN a = 'infinity' THEN 'idea'
ELSE 'bad idea'
end) stored
);
--测试时间。
insert into foo(a) values ('infinity');
insert into foo(a) values ('infinity1');
退货;
a | b
-----------+----------
infinity1 | bad idea
infinity | idea
当你尝试insert into foo(b) values ('infinity1')
yield Errors.
--ERROR: cannot insert into column "b" DETAIL: Column "b" is a generated column.