2011-10-30 39 views
5

我有一個創建PostgreSQL觸發器,基本上重定向插入到子表中。一旦我插入記錄,我想中止請求以避免重複的數據。我所知道的唯一方法是在觸發器中返回NULL。問題是我需要記錄被返回,所以我可以得到ID。如果我返回NULL,我得到... NULLPostgreSQL觸發器不返回任何東西

任何想法如何我可以讓一個觸發器中止一個操作,同時還返回NULL以外的東西?

+0

所以你試圖建立對將數據插入Y和Z表X觸發器,防止任何被插入X,但返回一些ID? –

+0

是的,我將數據分區爲繼承表。所以我不想在父表中有重複的行。我基本上希望這個過程是完全透明的。你處理父表,觸發器會在幕後做所有事情。從外面看沒有什麼變化。 –

回答

5

您的問題留有解釋空間。按照我的理解,您希望INSERT命令的RETURNING子句返回由序列生成的主鍵的值。

還有其他方法可以實現這一點。就像使用nextval()從序列中預先獲得下一個id並插入帶有拼寫出的id的行。
currval()/lastval()以獲得當前會話中的序列/任何序列的最近獲得的值。更多與此相關的回答:
PostgreSQL next value of the sequences?

您也可以使用RULE ... INSTEAD ..來達到此目的。

但是,要回答你的問題 - 如果這是事實,你的問題:它可以通過使用兩個觸發器來完成。一個BEFORE,一個AFTER INSERT。 兩者都是按照每個定義的一次交易觸發的,因此您的第一個表中的幻像行對任何人(觸發器除外)都是不可見的。

演示:

CREATE TABLE x (
    id serial PRIMARY KEY -- note the serial col. 
,name text 
); 

CREATE TABLE y (
    id integer PRIMARY KEY 
,name text 
); 


CREATE OR REPLACE FUNCTION trg_x_insbef() 
    RETURNS trigger AS 
$func$ 
BEGIN 
    INSERT INTO y SELECT (NEW).*; -- write to other table 
    RETURN NEW; 
END 
$func$ LANGUAGE plpgsql; 

CREATE TRIGGER insbef 
    BEFORE INSERT ON x 
    FOR EACH ROW EXECUTE PROCEDURE trg_x_insbef(); 


CREATE OR REPLACE FUNCTION trg_x_insaft() 
    RETURNS trigger AS 
$func$ 
BEGIN 
    DELETE FROM x WHERE id = NEW.id; -- delete row again. 
    RETURN NULL; 
END 
$func$ LANGUAGE plpgsql; 

CREATE TRIGGER insaft 
    AFTER INSERT ON x 
    FOR EACH ROW EXECUTE PROCEDURE trg_x_insaft(); 

呼叫在PSQL:

db=# INSERT INTO x (name) values('phantom') RETURNING id; 
id 
---- 
    1 
(1 row) 

INSERT 0 1 

db=# SELECT * FROM x; 
id | name 
----+------ 
(0 rows) 


db=# SELECT * FROM y; 
id | name 
----+--------- 
    1 | phantom 
(1 row) 
+0

謝謝!這是我想要的結果。我擔心的是性能,增加一行然後刪除它。我知道它不是什麼大熱門,只是看起來很雜亂。以其他方式做這件事是不可能的?謝謝您的幫助。 –

+0

我確信還有其他方法,但這是你要求的。我暗示在我的答案中使用nextval()。你看到了嗎? (加上鍊接。)這就是我可以做到的。 nextval()方法的缺點是:又一次調用服務器。所以這取決於情況會更快。我的例子是一個解決方法,但應該是完全安全的使用。 –