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
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();
为了使它更有效,在触发器定义中使用WHEN子句(从Postgres 9.0开始可用)。这样,触发器函数只在它实际有用时才执行。(假设我们可以让b IS NULL滑动if a IS NULL。) 在Postgres 12或更高版本中,GENERATED列可能是更好的解决方案。请参见jian's added answer。但是,请注意the manual中的这些限制: 生成表达式可以引用表中的其他列,但不能引用其他生成的列。使用的任何函数和运算符都必须是不可变的。不允许引用其他表。 这个触发器与DEFAULT值有细微的不同,因为b中的NULL总是被a派生的值替换,而DEFAULT只是默认值,可以被任何显式输入否决。 GENERATED列不允许输入以开始。
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')时产生错误。
--ERROR: cannot insert into column "b" DETAIL: Column "b" is a generated column.
2条答案
按热度按时间iyfjxgzm1#
对于简单的
DEFAULT
值,如the manual clearly states,这是不可能的:该值是任何无变量表达式(不允许子查询和对当前表中其他列的交叉引用)。
您可以改用trigger:
对于Postgres 10或更早版本,请改用
EXECUTE PROCEDURE ...
。为了使它更有效,在触发器定义中使用
WHEN
子句(从Postgres 9.0开始可用)。这样,触发器函数只在它实际有用时才执行。(假设我们可以让b IS NULL
滑动ifa IS NULL
。)在Postgres 12或更高版本中,
GENERATED
列可能是更好的解决方案。请参见jian's added answer。但是,请注意the manual中的这些限制:生成表达式可以引用表中的其他列,但不能引用其他生成的列。使用的任何函数和运算符都必须是不可变的。不允许引用其他表。
这个触发器与
DEFAULT
值有细微的不同,因为b
中的NULL总是被a
派生的值替换,而DEFAULT
只是默认值,可以被任何显式输入否决。GENERATED
列不允许输入以开始。biswetbf2#
在PostgreSQL 12或更高版本中,我们可以使用生成的列。
https://www.postgresql.org/docs/12/ddl-generated-columns.html示例:
--测试时间。
退货;
尝试
insert into foo(b) values ('infinity1')
时产生错误。