No Postgres 13, tenho uma tabela que é atualizada com frequência. No entanto, a consulta de atualização é bastante complicada e usa os mesmos valores várias vezes. Então, usar um CTE parece uma coisa bastante lógica a se fazer.
Um exemplo simplificado se parece com isso:
WITH my_cte AS (
SELECT
my_id,
CASE WHEN my_value1 > 100 THEN 50 ELSE 10 END AS my_addition
FROM my_table
WHERE my_id = $1
)
UPDATE my_table
SET my_value1 = my_table.my_value1 + my_cte.my_addition,
my_value2 = my_table.my_value2 + my_cte.my_addition
FROM my_cte
WHERE my_table.my_id = my_cte.my_id
Agora estou me perguntando: O que aconteceria se entre o SELECT
no CTE e o UPDATE
, a tabela fosse atualizada por outra consulta, alterando my_value1
assim, o cálculo de my_addition
ficasse desatualizado e errado quando UPDATE
isso acontecesse. Tal situação pode ocorrer? Ou o Postgres define um bloqueio implícito automaticamente?
Se o Postgres não faz mágica aqui e eu mesmo preciso cuidar disso: seria suficiente fazer FOR UPDATE
no SELECT
CTE?
Desculpe se não fui claro aqui: Não é que eu queira "ver" essas modificações simultâneas, eu quero evitá-las, ou seja, uma vez que o cálculo SELECT
é feito, nenhuma outra consulta pode modificar essa mesma linha até que UPDATE
seja feito.
Na vida real, o que eu zombei aqui CASE WHEN my_value1 > 100 THEN 50 ELSE 10 END
tem cerca de 20 linhas e eu preciso disso em cerca de 5 lugares no arquivo UPDATE
. Como sou um grande fã de "Não se repita", acho que um CTE é o caminho a percorrer. Ou existe uma maneira melhor de evitar copiar e colar em um UPDATE
sem CTE?