Estou me perguntando se é possível adicionar algum tipo de verificação para abortar um CTE de modificação de dados se uma atualização for parcialmente bem-sucedida. Em anexo está uma consulta mínima que representa o problema. Gostaria que a consulta falhasse se update_rows não atualizasse as 3 linhas especificadas na cláusula WHERE IN.
Isso é fácil de conseguir se esta consulta for reescrita como uma transação interativa, mas estou me perguntando se é possível conseguir isso mantendo as coisas como um único dado modificando o CTE.
with updated_rows as (
update some_table
set status = 'SUCCEEDED'
where id in ('a', 'b', 'c') and status = 'PENDING'
returning *
), more_updated_rows as (
update another_table
set total = total + 3
where completed = false
returning *
) select * from more_updated_rows
Uma consulta só falha se encontrar um erro. Você poderia provocar um na consulta externa:
Mas isso é estranho e o erro não terá sentido. A melhor solução é obter a contagem do resultado do lado do cliente e, caso não seja a desejada, reverter a transação e reportar um erro.
1º CTE - seleciona e conta a quantidade de linhas que serão atualizadas. Além disso, verifica se essas linhas são distintas (ou seja, todas as 3 linhas a serem atualizadas contêm valores de coluna diferentes, e não 3 dups de um valor) - isso pode ser removido quando a coluna do marcador é única e não anulável.
2º CTE - atualiza linhas com condição adicional que verifica a quantidade de linhas a serem atualizadas. Se a quantidade de linhas a serem atualizadas não for 3, nenhuma linha será atualizada.
A consulta externa retorna os valores de toda a verificação adicional do status da operação. Deve retornar (3,3,3) ou (0,0,0).
PS. A consulta não gera nenhum erro - a situação em que nem todos os valores da lista de valores estão presentes na tabela não é um erro, mas sim um fluxo normal do processo. Se for um erro lógico então uma exceção correspondente deve ser gerada pelo cliente (já tentei, o valor não bate, entro em pânico).