0

我想使用触发器对属性实现非空约束。这是我的代码:

create table mytable2(id int);

create or replace function p_fn() returns trigger as $prim_key$
begin
  if (tg_op='insert') then
    if (id is null) then
      raise notice 'ID cannot be null';
      return null;
    end if;
    return new;
  end if;
end;
$prim_key$ language plpgsql;

create trigger prim_key
before insert on mytable2
for each row execute procedure p_fn();

但是每当我尝试插入空值时,我都会收到一条错误消息,提示“控制已到达没有返回的触发过程结束”。我尝试将“return new”语句放在内部 IF 中,但它仍然给了我同样的错误。我究竟做错了什么?

4

2 回答 2

2

问题的直接原因是 PostgreSQL 字符串比较区分大小写。INSERT不一样insert。尝试:

IF tg_op = 'INSERT' THEN

建议

你只是提出一个通知。这允许控制流继续到过程中的下一行。您通常RAISE EXCEPTION应该中止执行并回滚事务。见RAISE。就目前而言,触发器将导致不满足要求的插入静默失败,这通常不是您想要的。

此外,您的触发器通常应该以 a 结尾,RAISE EXCEPTION如果它们总是应该在函数结束之前返回。这将帮助您更快地了解问题所在。

于 2013-04-14T10:47:06.340 回答
1

我会在已经提出的好建议中添加几件事:

  • 确保您也处理 UPDATE 案例
  • RAISE 使用正确的错误条件。我在下面给出了一个基本示例 - 有关更多格式选项,请参阅此处的文档。
  • 为清楚起见,我喜欢在触发器名称中至少包含表名

    CREATE OR REPLACE FUNCTION fn_validate_id_trigger() RETURNS TRIGGER AS
    $BODY$
    BEGIN
      IF (TG_OP IN ('INSERT', 'UPDATE')) THEN
        IF (NEW.id IS NULL) THEN
          RAISE not_null_violation;
        END IF;
      END IF;
      RETURN NULL;
    END;
    $BODY$
      LANGUAGE plpgsql;
    
    CREATE CONSTRAINT TRIGGER tr_mytable_validate_id
    AFTER INSERT OR UPDATE
    ON mytable2
    FOR EACH ROW EXECUTE PROCEDURE fn_validate_id_trigger();
    

更新:这现在是一个 CONSTRAINT 触发器,并在插入或更新后触发。在第一次编辑中,我提出了一个特定于列的触发器(UPDATE OF id)。这是有问题的,因为如果在表上执行的另一个触发器将列“id”更改为空,它不会触发。

同样,这不是处理约束的最有效方法,但很高兴知道。

于 2013-04-14T14:23:31.747 回答