通过触发器将具有默认值的列的值插入到另一个表中将得到空值

时间:2019-04-04 12:03:30

标签: postgresql

我在其中一列中有一个使用序列作为默认值的表。每当在此表中有插入内容时,我都想将序列的值插入到另一个表中。但是,在执行此操作时,我获得了由序列生成的值的空值。这是示例代码:

create sequence usq_test
  as bigint
  increment by 1
  start 1
  minvalue 1
  maxvalue 9223372036854775807
  no cycle
  owned by none;

create table test1(
  id bigint default nextval('usq_test') primary key,
   name text not null);

insert into test1(name) values ('test_name');
insert into test1(name) values ('test_name');
insert into test1(name) values ('test_name');

select * from test1;
| id |   name    |
|----|-----------|
|  1 | test_name |
|  2 | test_name |
|  3 | test_name |

现在,当我添加第二个表并定义触发函数时:

create table test2(id bigint primary key);

create or replace function ufn_insert_trg() returns trigger as
$$
begin
  insert into test2(id)
  values (NEW.id);
end;
$$ language plpgsql
;

create trigger utr_test1_insert
  after insert
  on test1
execute function ufn_insert_trg();

insert into test1(name) values ('test_name');

我得到:

[2019-04-04 14:00:45] [23502] ERROR: null value in column "id" violates not-null constraint
[2019-04-04 14:00:45] Detail: Failing row contains (null).
[2019-04-04 14:00:45] Where: SQL statement "insert into test2(id)
[2019-04-04 14:00:45] values (NEW.id)"
[2019-04-04 14:00:45] PL/pgSQL function ufn_insert_trg() line 3 at SQL statement

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

问题出在您的触发器上

create trigger utr_test1_insert
  after insert
  on test1
execute function ufn_insert_trg();

因为您没有明确说明触发器是行级还是语句级,所以默认情况下它将变为语句级触发器。

来自the documentation

  

每行

     

每份声明

     

这指定是否触发   对于受触发器影响的每一行应触发一次函数   事件,或每个SQL语句一次。如果未指定,则FOR   默认为“每个语句”。

而且根据the documentation,语句级触发器中的NEWOLD变量为NULL,这是有道理的,因为语句中可能影响了任何数量的行,因此NEWOLD引用任何特定的语句实际上没有任何意义-您要处理的是语句而不是特定的行。

这就是NEW.id为NULL的原因。通过将触发器更改为行级触发器,将为受影响的每一行触发该触发器,并按预期设置NEW / OLD变量。

所以:

create trigger utr_test1_insert
  after insert
  on test1
  for each row
execute function ufn_insert_trg();