Postgresql

在查詢中返回列是否已被目前查詢更改

  • March 8, 2022

我有一個像這樣的查詢

UPDATE my_table 
 SET my_value = 
   CASE WHEN random() > 0.5 THEN my_value * 2 ELSE my_value END
RETURNING *;

現在,在RETURNING語句中,我想要一個布爾值,指示my_value目前查詢是否已更改。

假設,我不能將之前的值my_value作為參數傳遞給查詢。

那麼,有沒有辦法獲得類似在 之後具有不同值的列的列表UPDATE?還是在 in 之前的狀態下獲取UPDATERETURNING

在我的範例中,我當然可以將結果放入random()CTE 中,例如

WITH random_cte AS (
   SELECT random() AS my_random
)
UPDATE my_table 
 SET my_value = 
   CASE WHEN my_random > 0.5 THEN my_value * 2 ELSE my_value END
FROM random_cte
RETURNING *, my_random > 0.5 AS value_changed;

但這會使查詢有些膨脹。所以我想知道我是否可以以更優雅的方式做到這一點?

這兩個查詢是不等價的。第一個查詢將評估每一行的**VOLATILE**函式random(),而第二個查詢在 CTE 中評估一次,因此my_random對所有行都是相同的。

不,CTE 不會被內聯。手冊:

但是,如果WITH查詢是非遞歸且無副作用的(即,它不SELECT 包含 volatile 函式),則可以將其折疊到父查詢中

大膽強調我的。

但這可能只是建構測試時的一個意外。

任一查詢都會更新所有行,即使沒有任何變化。

為了獲得value_changed可靠的結果,請比較 pre-UPDATE和 post-UPDATE值:

UPDATE my_table t
SET    my_value = CASE WHEN random() > 0.5 THEN t.my_value * 2 ELSE t.my_value END
FROM  (SELECT id, my_value FROM my_table) pre
WHERE  t.id = pre.id
RETURNING t.*, t.my_value IS DISTINCT FROM pre.my_value AS value_changed;

id是 PK 或任何其他(組合)唯一的非空列。

random() > 0.5可以true並且my_value仍然保持不變。想想NULL0

並發寫入負載下存在潛在的競爭條件。看:

如果您的案例真的那麼簡單(只有一個列要更新),您寧願從一開始就禁止空更新。看:

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