在具有生成列的表上使用 NEW
我有一個 PostgreSQL 12 數據庫,在一個表中我創建了一個帶有生成列的列,然後我有一個更新前觸發器,只有當
NEW
值DISTINCT
來自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。