2010-04-06 56 views
2

使用Postgresql。觸發器過程的一致性(在行觸發器之前)Postgresql

我嘗試使用TRIGGER過程對INSERT進行一些一致性檢查。

的問題是......

是否 「BEFORE INSERT FOR EACH ROW」 可以確保每一行插入 「檢查」 和 「插入」 一個又一個?我是否需要額外的表鎖來保持併發插入?

檢查新ROW1 - >插入ROW1 - >檢查新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 

或者我應該問, 我該如何使用Trigger來實現「主」或「唯一」約束式SQL。

+0

不要使用觸發器,速度太慢,不可靠:許多交易可以看到在選擇相同的結果,因此所有交易沒問題,你的數據不會是(部分)唯一的。 – 2010-04-07 06:38:29

回答

6

您的例子可以用一個唯一索引來完成:

CREATE UNIQUE INDEX uq_check_consistency ON product (name) WHERE NOT expired; 

這將導致第二個事務中的語句,將可能不可侵犯的約束,阻塞,直到第一個事務提交或回滾。

編輯補充

得到類似的(或更復雜)事務安全的行爲與觸發器,您可以創建一個CONSTRAINT trigger,即推遲,直到事務提交時。這些觸發功能必須AFTER觸發器,檢查你的約束是否被侵犯:

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(); 
0

爲什麼你不能使用唯一的密鑰來執行此操作?

+0

我想僅適用於某些特定列值的唯一約束。以上面的代碼爲例。如果所有產品的名稱都過期,則可以多次存在相同的產品名稱,但過期= false的產品必須具有唯一的名稱。 – elgcom 2010-04-06 20:08:55

+1

您可以創建唯一索引作爲Stephan Denne顯示的部分索引。見http://www.postgresql.org/docs/8.4/interactive/indexes-partial.html – Kuberchaun 2010-04-06 22:08:23

+0

謝謝,部分索引是確切的解決方案! 但我仍然不知道Trigger「FOR EACH ROW」是否可以保證順序UPDATE或INSERT,以便並發表INSERT或UPDATE不會違反約束。 – elgcom 2010-04-07 08:33:55