簡體   English   中英

PostgreSQL觸發器在插入或更新另一個表時更新表中的列

[英]Postgresql trigger to update a column in a table when another table gets inserted or updated

基本上我有table_a和table_b。 table_b是使用table_a中的功能制成的,並且它們共同共享section_id列和狀態。

table_a的section_id是主鍵,因此它是唯一的,但是table_b可以有多個section_id,但是它們共享相同的狀態

用戶插入並更新table_b,我想捕獲狀態更改回table_a

CREATE TRIGGER table_b_aiu
AFTER INSERT OR UPDATE
ON table_b
FOR EACH ROW
WHEN (((new.status = 100) OR (new.status = 200)))
EXECUTE PROCEDURE table_b_aiu();

CREATE OR REPLACE FUNCTION table_b_aiu()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE table_a a
SET status = 100
FROM table_b b
WHERE (b.status = 100 or b.status = 200) 
AND a.section_id = b.section_id;
    RETURN new; 
END;
$BODY$
 LANGUAGE plpgsql VOLATILE
 COST 100;

這樣做的問題是,它不僅更新了新近更新或插入的行,而且還更新了整個ENTIRE數據集,這是不希望的。 如何僅更新新行? 我嘗試將參數放在觸發上,但不接受new.section_id

嘗試此功能(雖然未測試)

CREATE OR REPLACE FUNCTION table_b_aiu()
RETURNS trigger AS
$BODY$
BEGIN
    UPDATE table_a
    SET status = 100
    WHERE section_id = NEW.section_id
    RETURN new;
END;
$BODY$

直到section_idtable_a上的主鍵,它才足夠。

有幾件事。 對於此類問題,訪問表定義進行測試絕對有幫助。 我已經模擬了我期望的桌子設計。 另外,包含“所需行為”也很有幫助(即,您打算始終將狀態設置為100嗎?無論table_b發生什么情況?)。 另外, update語句必須擊中整個table_a ,這就是為什么需要唯一約束來獲得唯一記錄的原因。 如果在應將SET status = new.statusSET status = new.status時錯誤地將狀態設置為100,那將是一個不同的問題(但看起來更新是“擊中整個表”,請參見下面的示例-特別是section_id=3 )。

希望以下內容可以說明正確的行為。 我懷疑您的觸發器應該設置status=new.status

CREATE TABLE table_a
(
 section_id serial
 , status integer
 , CONSTRAINT pk_table_a PRIMARY KEY (section_id)
);

CREATE TABLE table_b
(
 id serial
 , section_id integer
 , status integer
 , CONSTRAINT pk_table_b_aiu PRIMARY KEY (id)
 )
 ;


CREATE OR REPLACE FUNCTION table_b_aiu()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE table_a a
SET status = 100 -- intentional??
WHERE (new.status = 100 or new.status = 200) 
AND a.section_id = new.section_id;

    RETURN new; 
END;
$BODY$
 LANGUAGE plpgsql VOLATILE
 COST 100;

CREATE TRIGGER table_b_aiu
AFTER INSERT OR UPDATE
ON table_b
FOR EACH ROW
WHEN (((new.status = 100) OR (new.status = 200)))
EXECUTE PROCEDURE table_b_aiu();


INSERT INTO table_a (section_id, status)
values (1,100)
, (2,200)
, (3,201)
, (4, 202)
returning *;

| section_id | status |
| 1 | 100 |
| 2 | 200 |
| 3 | 201 |
| 4 | 202 |

INSERT INTO table_b (section_id, status)
values (1,101), (2,100), (3,200), (4,201)
returning *;

| id | section_id | status | 
| 1 | 1 | 101 | 
| 2 | 2 | 100 | 
| 3 | 3 | 200 |
| 4 | 4 | 201 |

select *
from table_a;

| section_id | status |
| 1 | 100 |
| 4 | 202 |
| 2 | 100 |
| 3 | 100 |

注意: new.status in (100,200)new.status in (100,200)是多余的,但是我認為您想確保安全(以防有人在沒有when語句的情況下設置觸發器。

我的建議:如果要將表本身的狀態選項限制為100/200,我建議為僅包含這些選項的status表創建外鍵。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM