Eu tenho uma consulta como
UPDATE my_table
SET my_value =
CASE WHEN random() > 0.5 THEN my_value * 2 ELSE my_value END
RETURNING *;
Agora, dentro da RETURNING
declaração eu gostaria de ter um booleano indicando se my_value
foi alterado pela consulta atual ou não.
Vamos supor que não posso passar o valor anterior de my_value
como parâmetro para a consulta.
Então, existe uma maneira de obter algo como uma lista de colunas que possuem valores diferentes após o UPDATE
? Ou obter os valores no estado antes UPDATE
em RETURNING
?
No meu exemplo, eu poderia, claro, colocar o resultado de random()
em um CTE como
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;
Mas isso aumentaria um pouco a consulta. Então eu estou querendo saber se eu poderia fazer isso de uma forma mais elegante?
As duas consultas não são equivalentes . A primeira consulta avaliaria a
VOLATILE
funçãorandom()
para cada linha, enquanto a segunda a avaliaria uma vez no CTE, portanto,my_random
é a mesma para todas as linhas.E não, o CTE não será embutido. O manual:
Minha ênfase em negrito.
Mas isso provavelmente é apenas um acidente na construção do seu teste.
Qualquer uma das consultas atualiza todas as linhas, mesmo que nada mude.
Para obter seus valores
value_changed
de forma confiável, compare os valores préUPDATE
e pósUPDATE
:id
sendo o PK ou qualquer outra (combinação de) coluna(s) única(s) não nula(s).random() > 0.5
pode sertrue
emy_value
ainda inalterado. Pense emNULL
ou0
.Há uma possível condição de corrida sob carga de gravação simultânea . Ver:
Se o seu caso de uso é realmente tão simples (apenas uma única coluna a ser atualizada), você prefere suprimir as atualizações vazias para começar. Ver: