T-SQL: usando um CASE em uma instrução UPDATE para atualizar certas colunas dependendo de uma condição

108

Estou me perguntando se isso é possível. Quero atualizar a coluna x se uma condição for verdadeira, caso contrário, a coluna y seria atualizada

UPDATE table SET
     (CASE (CONDITION) WHEN TRUE THEN columnx
                       ELSE columny
      END)
= 25

Procurei por todo o lado, experimentei algumas coisas e não consigo encontrar uma solução. Acho que não é possível, mas pensei em perguntar aqui e ver se alguém já fez isso antes. Desde já, obrigado.

pqsk
fonte
Supondo que todos estejam na mesma mesa, sim. Você sempre pode executá-lo em uma transação e reverter em caso de erro, para ver por si mesmo.
OMG Ponies
Não tenho certeza do que você quer dizer. Eu tentei colocar uma condicional para a coluna, mas não funcionou. Funciona para uma instrução select, mas não para uma instrução update. (Select (case (condition) when true then columnx else columny end) from myTable .... a atualização não funciona e eu posso ver o porquê. parece uma maneira de fazer isso funcionar.
pqsk

Respostas:

188

Você não pode usar uma condição para alterar a estrutura da sua consulta, apenas os dados envolvidos. Você poderia fazer isso:

update table set
    columnx = (case when condition then 25 else columnx end),
    columny = (case when condition then columny else 25 end)

Isso é semanticamente igual, mas lembre-se de que ambas as colunas sempre serão atualizadas . Isso provavelmente não causará problemas, mas se você tiver um alto volume transacional, poderá causar problemas de simultaneidade.

A única maneira de fazer especificamente o que você está pedindo é usar SQL dinâmico. No entanto, isso é algo que eu encorajo você a ficar longe. A solução acima quase certamente será suficiente para o que você procura.

Adam Robinson
fonte
Eu concordo com o SQL dinâmico. Então, meus dados serão afetados? Quer dizer, não quero que seja alterado para certas condições. Então, ele apenas reinsere o que já está lá? A quantidade de acessos ao banco de dados pode não ser tão ruim.
pqsk
@pqsk: Isso não deve afetar seus dados, apenas reinserir o que já está lá para a coluna que não deve ser afetada.
Adam Robinson
Obrigado. Eu vou continuar com isso. Tão simples que até um homem das cavernas pode fazer isso. haha.
pqsk
1
@AdamRobinson 1,5 anos se passaram, você conhece uma maneira mais eficiente de atualizar apenas uma coluna
@Somebodyisintrouble: A única maneira de atualizar uma coluna é usar uma consulta diferente.
Adam Robinson
23
UPDATE  table
SET     columnx = CASE WHEN condition THEN 25 ELSE columnx END,
        columny = CASE WHEN condition THEN columny ELSE 25 END
Quassnoi
fonte
1
Você acabou de copiar a resposta de Adam ou foi tirada de outro lugar? haha. Só notei isso.
pqsk
1
@pqsk: Nossas respostas tiveram um intervalo de aproximadamente 1 minuto, então eu imagino que cliquei em enviar um pouco mais rápido;)
Adam Robinson
23
@pqsk: sim, acabei de copiar a resposta de Adam, 23segundos antes de ele postar. Sou um redator rápido!
Quassnoi
2
@pqsk: se você colocar o cursor sobre o * min ago, ele mostrará a hora exata em que foi postado.
Quassnoi
2
Para ser justo, mesmo que ambos sejam iguais: se Adam tivesse saído depois do seu, ele elaborou um pouco mais. É por isso que marquei o dele como a resposta. Obrigado.
pqsk de
4

insira a descrição da imagem aqui

Quero alterar ou atualizar meu ContactNo para 8018070999, onde há 8018070777 usando a declaração Case

update [Contacts] set contactNo=(case 
when contactNo=8018070777 then 8018070999
else
contactNo
end)

insira a descrição da imagem aqui

Debendra Dash
fonte
1
para isso, por que não usar esta consulta UPDATE [Contatos] SET contactNo = 8018070999 WHERE contactNo = 8018070777
NewGuy
4

Eu sei que esta é uma questão muito antiga, mas funcionou para mim:

UPDATE TABLE SET FIELD1 =
CASE 
WHEN FIELD1 = Condition1 THEN 'Result1'
WHEN FIELD1 = Condition2 THEN 'Result2'
WHEN FIELD1 = Condition3 THEN 'Result3'
END;

Saudações

Victor Eduardo Salazar Ramirez
fonte
1

Eu sei que esta é uma questão muito antiga e o problema está marcado como corrigido. Porém, se alguém com um caso como o meu em que a tabela possui gatilho para registro de dados em eventos de atualização, isso causará problema. Ambas as colunas obterão a atualização e o registro criará entradas inúteis. Do jeito que eu fiz

IF (CONDITION) IS TRUE
BEGIN
    UPDATE table SET columnx = 25
END
ELSE
BEGIN
    UPDATE table SET columny = 25
END

Agora, isso tem outro benefício de não ter gravações desnecessárias na tabela, como as soluções acima.

Áspero
fonte
este é um bom ponto e uma boa alternativa! Não estou mais trabalhando com o código original que leva a este segmento, mas é sempre bom ter soluções diferentes e acho que esta é uma boa solução
pqsk
-1

Acredito que você pode omitir a atualização das colunas "não desejadas" ajustando as outras respostas da seguinte forma:
update table set columnx = (case when condition1 then 25 end), columny = (case when condition2 then 25 end)

Pelo que entendi, isso só será atualizado quando a condição for atendida.

Depois de ler todos os comentários, este é o mais eficiente:
Update table set ColumnX = 25 where Condition1 Update table set ColumnY = 25 where Condition1

Tabela de amostra:
CREATE TABLE [dbo].[tblTest]( [ColX] [int] NULL, [ColY] [int] NULL, [ColConditional] [bit] NULL, [id] [int] IDENTITY(1,1) NOT NULL ) ON [PRIMARY]
Dados de amostra:
Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 0) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 0) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 1) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 1) Insert into tblTest (ColX, ColY, ColConditional) values (1, null, null) Insert into tblTest (ColX, ColY, ColConditional) values (2, null, null) Insert into tblTest (ColX, ColY, ColConditional) values (null, 1, null) Insert into tblTest (ColX, ColY, ColConditional) values (null, 2, null)

Agora suponho que você possa escrever uma condicional que lida com nulos. Para meu exemplo, estou assumindo que você escreveu uma condicional que avalia como True, False ou Null. Se precisar de ajuda com isso, me avise e eu farei o meu melhor.

Agora, a execução dessas duas linhas de código altera de fato X para 25 se e somente se ColConditional for True (1) e Y para 25 se e somente se ColConditional for False (0)

Update tblTest set ColX = 25 where ColConditional = 1 Update tblTest set ColY = 25 where ColConditional = 0

PS O caso nulo nunca foi mencionado na pergunta original ou em qualquer atualização da pergunta, mas como você pode ver, esta resposta muito simples trata disso de qualquer maneira.

John Greiner
fonte
1
Isso realmente não funciona. Por um lado, se a coluna permite nulos, quando a condição não é atendida, um valor nulo é atribuído. No caso em que nulos não são permitidos, a atualização falhará. Sua consulta "eficiente" final é sql inválido, pelo menos em TSQL. Você testou isso em um motor específico e funcionou para você?
pqsk
Testei isso no SQL Server 2005 e funciona perfeitamente conforme mostrado. Gostaria de saber por que foi rejeitado e um exemplo mostrando o valor NULL sendo atualizado, porque no meu teste acima, o valor nulo não é atualizado. Sempre achei que a resposta mais simples é a melhor e, se estou lidando com um banco de dados com milhões de registros, com certeza não quero atualizar linhas desnecessárias.
John Greiner