Postgresql

在具有生成列的表上使用 NEW

  • August 25, 2020

我有一個 PostgreSQL 12 數據庫,在一個表中我創建了一個帶有生成列的列,然後我有一個更新前觸發器,只有當NEWDISTINCT來自OLD值時才會觸發,基本上是這樣的:

BEFORE UPDATE 
ON public.some_table
FOR EACH ROW
WHEN (NEW IS DISTINCT FROM OLD)
EXECUTE PROCEDURE public.update_modified_column();

但是,儘管正確,但此程式碼不適用於生成的列,並出現以下錯誤:

BEFORE 觸發器的 WHEN 條件不能引用 NEW 生成的列

所以我的問題是:有什麼方法可以使用NEW生成列的表,不必指定該表中未生成的每一列?

它可能需要指定要排除的列,而不是相反。

另外,我知道生成表的一個潛在替代方法是視圖(這不是同一件事,但對於我的案例來說足夠接近),但我不能使用視圖,因為我需要一些東西來跟踪列是否允許t 允許空值,不幸的是視圖不這樣做。

使用帶有插入/更新前觸發器的普通列來計算列,並將列設置為NOT NULL預設(對於我的案例 ofc),基本上解決了這個問題;但是,我將保留這個問題,看看是否有針對生成的列的任何解決方案,因為它們是一個更優雅的解決方案。

這很簡單:改用AFTER觸發器。然後將計算列值。

另一方面,您的答案表明您需要一個BEFORE觸發器,因為您想修改NEW.

因此,最好的解決方案可能是使用帶有排除生成列的條件的BEFORE觸發器:WHEN

WHEN ((NEW.col1, NEW.col2, ...)
     IS DISTINCT FROM
     (OLD.col1, OLD.col2, ...))

在 Laurenz Albe 建議使用 AFTER TRIGGER 之後,我重新審視了它的使用,看看為什麼我之前嘗試過它時它沒有工作,並發現 NEW 和 OLD 不能用於後觸發器呼叫的觸發器函式中修改這些值(在文件中有描述)。因此,在更新前觸發器中工作的函式將在更新後觸發器中不起作用,如果它使用 NEW/OLD 來更改值,這意味著操作 NEW.modified = now() 不起作用,儘管沒有拋出任何錯誤.

因此,我已將 update_modified_column() 函式修改為:

BEGIN
EXECUTE format('UPDATE %I.%I SET modified = now() WHERE id= %L', TG_TABLE_SCHEMA, TG_TABLE_NAME, NEW.id);
RETURN NEW;
END;

這確實按預期工作,但是除了需要存在名為 modified 的列之外,它現在還需要一個名為 id 的唯一列,因此不像舊列那樣簡單和通用。應該可以通過程式方式獲取主鍵,但是對於我的案例來說這已經足夠好了,因為我所有的表都使用了一個名為 id 的欄位。

無論哪種方式供我個人使用,我都認為該問題已得到解答,因為該問題有兩種解決方案,並且解釋了為什么生成的列不適用於 BEFORE UPDATE。

引用自:https://dba.stackexchange.com/questions/274150