触发器过程的一致性(行触发器之前)Postgresql

触发器过程的一致性(行触发器之前)Postgresql,postgresql,stored-procedures,triggers,Postgresql,Stored Procedures,Triggers,使用Postgresql 我尝试使用触发器过程对INSERT进行一些一致性检查 问题是 “每行插入前”是否可以确保每行依次插入“选中”和“插入”?我需要额外的表锁才能从并发插入中生存吗 检查新行1->插入行1->检查新行2->插入行2 -- -- -- unexpired product name is unique. CREATE TABLE product ( "name" VARCHAR(100) NOT NULL, "expired" BOOLEAN NOT N

使用Postgresql

我尝试使用触发器过程对INSERT进行一些一致性检查

问题是

“每行插入前”是否可以确保每行依次插入“选中”和“插入”?我需要额外的表锁才能从并发插入中生存吗

检查新行1->插入行1->检查新行2->插入行2

--
--

-- unexpired product name is unique.
CREATE TABLE product (
  "name"    VARCHAR(100) NOT NULL,
  "expired" BOOLEAN      NOT NULL
);

CREATE OR REPLACE FUNCTION check_consistency() RETURNS TRIGGER AS $$
  BEGIN
    IF EXISTS (SELECT * FROM product WHERE name=NEW.name AND expired='false') THEN
      RAISE EXCEPTION 'duplicated!!!';              
    END IF;
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_check_consistency
BEFORE INSERT ON product
  FOR EACH ROW EXECUTE PROCEDURE check_consistency();

--
INSERT INTO product VALUES("prod1", true);
INSERT INTO product VALUES("prod1", false);
INSERT INTO product VALUES("prod1", false); // exception!
这没关系

 name | expired
 ==============
 p1   |  true
 p1   |  true
 p1   |  false
这不好

 name | expired
 ==============
 p1   |  true
 p1   |  false
 p1   |  false
或者我应该问一下,
如何使用触发器实现“主”或“唯一”约束,如SQL。

为什么不能使用唯一键来强制执行此约束

您的示例可以使用唯一索引完成:

CREATE UNIQUE INDEX uq_check_consistency ON product ( name ) WHERE NOT expired;
这将导致第二个事务中出现一条语句,该语句可能会使约束不受侵犯,直到第一个事务提交或回滚为止

编辑以添加

要使用触发器获得类似(或更复杂)的事务安全行为,可以创建一个延迟到事务提交时间的。这些触发函数需要在触发之后执行,以检查是否违反了约束:

CREATE OR REPLACE FUNCTION after_check_consistency() RETURNS TRIGGER AS $$
  BEGIN
    IF (SELECT count(*) FROM product WHERE name=NEW.name AND expired='false') > 1 THEN
      RAISE EXCEPTION 'duplicated!!!';              
    END IF;
    RETURN NULL;
  END;
$$ LANGUAGE plpgsql;


CREATE CONSTRAINT TRIGGER trigger_check_consistency
AFTER INSERT OR UPDATE ON product
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW EXECUTE PROCEDURE after_check_consistency();

我只想对某些特定的列值应用唯一约束。以上面代码中的示例为例。如果相同的产品名称都已过期,则它们可以多次存在,但expired=false的产品必须具有唯一名称。您可以创建唯一索引作为部分索引,如Stephan Denne所示。看,谢谢,部分索引正是解决方案!!!但是我仍然不知道触发器“FOR EACH ROW”是否可以保证顺序更新或插入,这样并发表插入或更新就不会违反约束。不要使用触发器,太慢而且不可靠:许多事务可以在SELECT中看到相同的结果,所以所有事务都可以,并且您的数据(部分)不会唯一。