Use CASE para selecionar colunas na consulta UPDATE?

13

Posso usar CASEpara escolher quais colunas serão exibidas em uma SELECTconsulta (Postgres), assim:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

É possível algo semelhante ao executar uma UPDATEconsulta no Postgres (por exemplo, escolher quais colunas devem ser atualizadas)? Presumo que não, porque não consegui encontrar nada sobre isso, mas talvez alguém tenha uma alternativa inteligente (além de usar um procedimento ou atualizar cada coluna usando a CASEpara determinar se o valor da coluna deve receber um novo valor ou simplesmente reatribuir o valor existente valor). Se não houver uma alternativa fácil, é claro que também aceitarei isso como resposta.

Informações adicionais : no meu caso, tenho 14 colunas em potencial que podem ser atualizadas, com apenas uma sendo atualizada por linha correspondente (a tabela a ser atualizada é unida a outra na consulta). A quantidade de linhas a serem atualizadas provavelmente variará, pode ser de dezenas ou centenas. Acredito que existem índices para as condições de união.

newenglander
fonte

Respostas:

26

Se você especificar que uma coluna deve ser atualizada, ela sempre será atualizada, mas é possível alterar o valor digitado condicionalmente e colocar de volta os valores originais, dependendo de suas condições. Algo como:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Portanto, se as condições não forem adequadas para uma atualização de uma coluna específica, você apenas retroalimentará o valor atual.

Note que cada linha combinado vai ver uma atualização (mesmo se todas as colunas acabar ficando definido para os valores que eles já têm) a menos que você explicitamente portão esta circunstância em que você filtrando e WHERE, que poderia ser um problema de desempenho (haverá seja uma gravação, os índices serão atualizados, os acionadores apropriados serão acionados, ...) se não forem atenuados.

David Spillett
fonte
Obrigado pela dica sobre tudo que está sendo atualizado; se isso for lento, posso aceitar a sugestão de @Colin 't Hart para ter várias instruções de atualização.
newenglander
Você pode atenuar esse problema, certificando-se de que suas cláusulas ON e WHERE filtrem todas as linhas onde não são necessárias alterações, mas isso pode significar repetir todas as suas condições na cláusula SET e na cláusula WHERE (a menos que haja uma verificação geral mais simples de que é 100% equivalente a todas essas condições combinadas). Nesse ponto, esse método ainda pode ser mais eficiente, mas o método de várias atualizações pode ser mais fácil de manter.
precisa saber é o seguinte
Esteja ciente também que atualizar uma coluna para o mesmo valor fará com que refazer a ser criado, consulte orainternals.wordpress.com/2010/11/04/...
Colin 't Hart
@ Colin: Sim, qualquer atualização passará pelo log de transações do banco de dados, incluindo atualizações que são essencialmente NoOps devido à atualização de campos para os mesmos valores que tinham antes. Além do potencial para um problema de desempenho imediato, isso pode ser um fator importante se você usar replicação, backups diferenciais, envio de logs e assim por diante, pois as operações extras de atualização de linha aumentarão o espaço / largura de banda necessária para eles.
precisa saber é o seguinte
Obrigado a vocês pelas dicas, no meu caso, a declaração de atualização única funcionou bem.
newenglander
5

Quantas combinações diferentes de colunas para atualizar você possui? Quantas linhas da tabela inteira serão atualizadas? Existem índices para acesso rápido às linhas para atualização?

Dependendo das respostas a essas perguntas, você poderá executar várias instruções de atualização, uma para cada coluna que deseja atualizar e colocar a condição no valor dessa coluna na cláusula where da atualização para que zero linhas sejam atualizadas se essa coluna tem o valor errado.

Tente pensar com base em conjunto, não presuma que a atualização precise atualizar uma única linha encontrada pela chave primária.

Colin 't Hart
fonte
Obrigado pela resposta. Adicionei mais informações à minha pergunta, espero que seja compreensível. Essa é uma boa alternativa com várias instruções de atualização (eu preferiria uma instrução de atualização, mas vejo que há uma vantagem).
newenglander
Esta pode ser a resposta que estou procurando, mas você deseja colocar a atualização column_x = new_value_for_x em que @val = 0. Eu posso experimentar algo assim. Parece Engraçado. Não é mais fácil fazer se val = 0 começar a atualização column_x = new_value_for_x etc.
CashCow
-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then '[email protected]'
       when FName = 'Riddick' then '[email protected]'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end
user134695
fonte
Esta atualização é apenas uma coluna, enquanto o solicitante deseja saber como atualizar colunas diferentes, dependendo das condições.
Colin 't Hart