2011-10-30 33 views
5

Tôi có một kích hoạt PostgreSQL trên tạo ra về cơ bản chuyển hướng chèn vào các bảng phụ. Khi tôi chèn bản ghi, tôi muốn KHÔNG THỂ yêu cầu để tránh dữ liệu trùng lặp. Cách duy nhất (mà tôi biết) để làm điều này là trả lại NULL trong trình kích hoạt. Vấn đề là tôi cần bản ghi được trả lại để tôi có thể nhận được ID. Nếu tôi trả lại NULL, tôi nhận được ... NULL.Trình kích hoạt PostgreSQL không trả về bất cứ điều gì

Bất kỳ ý tưởng nào về cách tôi có thể kích hoạt một hoạt động trong khi vẫn trả lại thứ gì đó khác với NULL?

+0

Vì vậy, bạn đang cố gắng để xây dựng một kích hoạt trên bảng X chèn dữ liệu vào Y và Z, ngăn cản bất cứ điều gì từ được chèn vào X, nhưng trả về một số ID? –

+0

Có, tôi đang phân vùng dữ liệu thành các bảng được kế thừa. Vì vậy, tôi không muốn một hàng trùng lặp trong bảng cha. Về cơ bản tôi muốn quy trình này hoàn toàn minh bạch. Bạn đối phó với bảng cha, trình kích hoạt làm mọi thứ đằng sau hậu trường. Không có gì thay đổi từ bên ngoài nhìn vào. –

Trả lời

5

Câu hỏi của bạn rời khỏi phòng để diễn giải. Theo cách tôi hiểu, bạn muốn mệnh đề RETURNING của lệnh INSERT để trả về giá trị của khóa chính được tạo bởi một chuỗi.

Có nhiều cách khác để đạt được điều này. Giống như sử dụng nextval() để nhận được id tiếp theo từ trình tự trước và chèn hàng có số id được viết ra.
HOẶC currval()/lastval() để nhận giá trị thu được gần đây nhất cho một chuỗi/chuỗi bất kỳ trong phiên hiện tại. Xem thêm trong câu trả lời có liên quan này:
PostgreSQL next value of the sequences?

Bạn cũng có thể sử dụng RULE ... INSTEAD .. cho mục đích này.

Nhưng, để trả lời câu hỏi của bạn - nếu đó là, trên thực tế, câu hỏi của bạn: nó có thể được thực hiện bằng cách sử dụng hai trình kích hoạt. Một BEFORE, một AFTER INSERT. Cả hai đều được kích hoạt trong một giao dịch cho mỗi định nghĩa, do đó hàng ma trong bảng đầu tiên của bạn không bao giờ được hiển thị cho bất kỳ ai (ngoại trừ trình kích hoạt).

Demo:

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

Gọi trong 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

Cảm ơn! Đây là kết quả chính xác mà tôi muốn. Mối quan tâm của tôi là hiệu suất, thêm hàng và sau đó xóa nó. Tôi biết nó không phải là một hit lớn, chỉ có vẻ lộn xộn. Bạn không thể làm điều này theo bất kỳ cách nào khác? Cảm ơn đã giúp đỡ. –

+0

Tôi chắc chắn có một cách khác, nhưng đó là những gì bạn yêu cầu. Tôi gợi ý sử dụng nextval() trong câu trả lời của tôi. Bạn có thấy điều đó không? (Thêm liên kết.) Đó là cách tôi có thể làm điều đó. Nhược điểm với 'nextval()': một cuộc gọi khác đến máy chủ. Vì vậy, nó phụ thuộc vào hoàn cảnh sẽ nhanh hơn. Ví dụ của tôi là một cách giải quyết nhưng phải hoàn toàn an toàn để sử dụng. –

Các vấn đề liên quan