T-SQL: Utilisation d'un CASE dans une instruction UPDATE pour mettre à jour certaines colonnes en fonction d'une condition

108

Je me demande si cela est possible du tout. Je souhaite mettre à jour la colonne x si une condition est vraie, sinon la colonne y serait mise à jour

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

J'ai cherché partout, essayé certaines choses et je suis incapable de trouver une solution. Je pense que ce n'est pas possible, mais j'ai pensé que je demanderais ici et voir si quelqu'un l'a déjà fait. Merci d'avance.

pqsk
la source
En supposant que tout soit dans le même tableau, oui. Vous pouvez toujours l'exécuter dans une transaction, et revenir en arrière en cas d'erreur, pour voir par vous-même.
OMG Ponies
Je ne sais pas ce que tu veux dire. J'ai essayé de mettre un conditionnel pour la colonne, mais cela ne fonctionne pas. Cela fonctionne pour une instruction select, mais pas pour une instruction update. (Select (case (condition) when true then columnx else columny end) from myTable .... la mise à jour ne fonctionne pas, et je peux voir pourquoi. Cela semble être un moyen de faire en sorte que cela fonctionne.
pqsk

Réponses:

188

Vous ne pouvez pas utiliser une condition pour modifier la structure de votre requête, uniquement les données concernées. Vous pouvez faire ceci:

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

C'est sémantiquement le même, mais gardez simplement à l'esprit que les deux colonnes seront toujours mises à jour . Cela ne vous posera probablement aucun problème, mais si vous avez un volume transactionnel élevé, cela pourrait entraîner des problèmes de concurrence.

La seule façon de faire spécifiquement ce que vous demandez est d'utiliser du SQL dynamique. C'est cependant quelque chose que je vous encourage à éviter. La solution ci-dessus sera presque certainement suffisante pour ce que vous recherchez.

Adam Robinson
la source
Je suis d'accord sur le SQL dynamique. Alors mes données seront-elles affectées? Je veux dire que je ne veux pas que cela change pour certaines conditions. Donc, il va simplement réinsérer ce qui est déjà dedans? La quantité de hits dans la base de données n'est peut-être pas si mauvaise.
pqsk
@pqsk: Cela ne devrait pas affecter vos données, il devrait simplement réinsérer ce qui est déjà là pour la colonne qui n'est pas censée être affectée.
Adam Robinson
Merci. Je vais aller avec ça. Si simple, même un homme des cavernes peut le faire. haha.
pqsk
1
@AdamRobinson 1,5 ans se sont écoulés connaissez-vous un moyen plus efficace de mettre à jour une seule colonne
@Somebodyisintrouble: La seule façon de mettre à jour une colonne est d'utiliser une requête différente.
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
la source
1
Avez-vous juste copié la réponse d'Adam, ou est-ce que cela a été pris ailleurs? haha. Je viens de remarquer ça.
pqsk
1
@pqsk: Nos réponses étaient espacées d'environ 1 minute, alors j'imagine que j'ai juste cliqué sur Soumettre un peu plus vite;)
Adam Robinson
23
@pqsk: oui, je viens de copier la réponse d'Adam, 23quelques secondes avant qu'il ne la publie. Je suis un copypaster rapide!
Quassnoi
2
@pqsk: si vous placez le curseur sur le * min ago, il vous montrera l'heure exacte à laquelle il a été publié.
Quassnoi
2
Pour être juste, même si les deux sont les mêmes: si Adam était sorti après le vôtre, il en a élaboré un peu plus. C'est pourquoi j'ai marqué sa réponse. Merci quand même.
pqsk
4

entrez la description de l'image ici

Je souhaite modifier ou mettre à jour mon ContactNo en 8018070999 où il y a 8018070777 à l'aide de l'instruction Case

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

entrez la description de l'image ici

Debendra Dash
la source
1
pour cela pourquoi ne pas utiliser cette requête UPDATE [Contacts] SET contactNo = 8018070999 WHERE contactNo = 8018070777
NewGuy
4

Je sais que c'est une question très ancienne, mais cela a fonctionné pour moi:

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

Cordialement

Victor Eduardo Salazar Ramirez
la source
1

Je sais que c'est une question très ancienne et le problème est marqué comme résolu. Cependant, si quelqu'un avec un cas comme le mien où la table a un déclencheur pour la journalisation des données sur les événements de mise à jour, cela posera un problème. Les deux colonnes recevront la mise à jour et le journal fera des entrées inutiles. La façon dont j'ai fait

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

Maintenant, cela a un autre avantage qu'il n'a pas d'écritures inutiles sur la table comme les solutions ci-dessus.

Dur
la source
c'est un bon point et une bonne alternative! Je ne travaille plus sur le code original qui mène à ce fil, mais c'est toujours bien d'avoir des solutions différentes et je pense que c'est une bonne solution
pqsk
-1

Je pense que vous pouvez omettre de mettre à jour les colonnes "non souhaitées" en ajustant les autres réponses comme suit:
update table set columnx = (case when condition1 then 25 end), columny = (case when condition2 then 25 end)

Si je comprends bien, cela ne sera mis à jour que lorsque la condition sera remplie.

Après avoir lu tous les commentaires, c'est le plus efficace:
Update table set ColumnX = 25 where Condition1 Update table set ColumnY = 25 where Condition1

Exemple de tableau:
CREATE TABLE [dbo].[tblTest]( [ColX] [int] NULL, [ColY] [int] NULL, [ColConditional] [bit] NULL, [id] [int] IDENTITY(1,1) NOT NULL ) ON [PRIMARY]
Exemple de données:
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)

Maintenant, je suppose que vous pouvez écrire un conditionnel qui gère les valeurs nulles. Pour mon exemple, je suppose que vous avez écrit un tel conditionnel qui donne la valeur True, False ou Null. Si vous avez besoin d'aide, faites-le moi savoir et je ferai de mon mieux.

Maintenant, exécuter ces deux lignes de code modifie en fait X à 25 si et seulement si ColConditional est True (1) et Y à 25 si et seulement si ColConditional est False (0)

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

PS Le cas nul n'a jamais été mentionné dans la question originale ou dans les mises à jour de la question, mais comme vous pouvez le voir, cette réponse très simple les gère quand même.

John Greiner
la source
1
Cela ne fonctionne pas vraiment. D'une part, si la colonne autorise les valeurs nulles, lorsque la condition n'est pas remplie, une valeur nulle est attribuée. Dans le cas où les valeurs nulles ne sont pas autorisées, la mise à jour échouera. Votre requête finale "efficace" est SQL invalide, au moins dans TSQL. Avez-vous testé cela sur un moteur spécifique et cela a fonctionné pour vous?
pqsk
J'ai testé cela sur SQL Server 2005 et cela fonctionne parfaitement comme indiqué. Je voudrais certainement savoir pourquoi il a été voté à la baisse et un exemple montrant la valeur NULL mise à jour, car dans mon test ci-dessus, la valeur nulle n'est pas mise à jour. J'ai toujours pensé que la réponse la plus simple est la meilleure et si je traite avec une base de données avec des millions d'enregistrements, je ne veux certainement pas mettre à jour des lignes inutiles.
John Greiner