Commutation de valeurs dans une colonne avec une instruction de mise à jour

12

Vous constatez qu'une erreur dans un système a incorrectement nommé les hommes (M) en tant que femmes (W) et vice versa dans la base de données. Les colonnes ne permettent qu'un seul caractère. Sans utiliser de tables temporaires, écrivez une requête de mise à jour pour résoudre ce problème.

Cette question a été posée lors d'une récente interview que j'ai eue, et j'entre dans d'autres interviews qui peuvent avoir des questions similaires, donc je voulais avoir une idée de la façon de gérer cela.

SethOui
la source
6
Vous a-t-on demandé d'assumer un produit de base de données particulier? par exemple MySQL, SQL Server, Oracle, PostgreSQL ...?
Paul White 9
Votre système a-t-il lu les nouvelles directives de la communauté? : \
AER

Réponses:

22

Vous souhaitez utiliser une CASEexpression d'un certain type.

Dans SQL Server, le code ressemblerait à ceci:

UPDATE TableName
SET gender = CASE WHEN gender = 'M' THEN 'W' 
                  WHEN gender = 'W' THEN 'M'
                  ELSE gender END

Edit: Comme indiqué dans les commentaires (et certaines des autres réponses), ELSE n'est pas nécessaire si vous mettez une clause WHERE sur la déclaration.

UPDATE TableName
SET gender = CASE WHEN gender = 'M' THEN 'W' 
                  WHEN gender = 'W' THEN 'M' END
WHERE gender IN ('M','W')

Cela évite les mises à jour inutiles. La chose importante dans les deux cas est de se rappeler qu'il existe des options autres que M&W (NULL par exemple) et que vous ne voulez pas mettre des informations erronées. Par exemple:

UPDATE TableName
SET gender = CASE WHEN gender = 'M' THEN 'W' 
                  ELSE 'M' END

Cela remplacerait tout NULL (ou tout autre sexe possible) par «M», ce qui serait incorrect.


Quelques autres options seraient

/*Simple form of CASE rather than Searched form*/
UPDATE TableName
SET    gender = CASE gender
                  WHEN 'M' THEN 'W'
                  WHEN 'W' THEN 'M'
                END
WHERE  gender IN ( 'M', 'W' );

Et un plus concis

/*For SQL Server 2012+*/
UPDATE TableName
SET    gender = IIF(gender = 'M', 'W', 'M')
WHERE  gender IN ( 'M', 'W' ); 
Kenneth Fisher
la source
1
Vous pouvez remplacer le IIF()par IF()et cela fonctionnerait dans MySQL;)
ypercubeᵀᴹ
9

Dans Oracle, vous pouvez utiliser un CASE comme les autres réponses ont:

UPDATE TableName
SET gender = CASE WHEN gender = 'M' THEN 'W' 
                  WHEN gender = 'W' THEN 'M'
             END
WHERE gender in ('M','W');

Vous pouvez également utiliser un DECODE:

UPDATE TableName SET gender = DECODE(gender,'M','W','W','M')
WHERE gender in ('M','W');
Leigh Riffel
la source
5

Pour basculer entre seulement deux valeurs, vous pouvez également essayer cette astuce, qui n'utilise pas d' CASEexpression (en supposant Transact-SQL ici):

UPDATE
  YourTable
SET
  Gender = CHAR(ASCII('M') + ASCII('W') - ASCII(Gender))
WHERE
  Gender IN ('M', 'W')
;

En fonction de la valeur actuelle de Gender, ASCII(Gender)annulera l'un ASCII('M')ou ASCII('W')l'autre, laissant l'autre code être transformé par la CHAR()fonction en retour au caractère correspondant.

Je laisse cela juste pour comparaison, cependant. Bien que cette option puisse avoir une apparence d'élégance, une solution utilisant une CASEexpression serait sans doute plus lisible et donc plus facile à maintenir, et il serait certainement plus facile de l'étendre à plus de deux valeurs.

Andriy M
la source
2
Espérons que tous les Met Wont été saisis en majuscules pour éviter que des résultats inattendus 7ou `-` n'apparaissent.
Martin Smith
@MartinSmith: Très bon point. Si ce n'était pas le cas, nous devrons le remplacer ASCII(Gender)par ASCII(UPPER(Gender)), ce qui est moins élégant, mais pas beaucoup.
Andriy M
@MartinSmith s'il y a des m et w en minuscules, ne seront-ils pas rejetés par la WHEREclause?
ypercubeᵀᴹ
1
@ YperSillyCubeᵀᴹ - Uniquement dans le cas de classements sensibles (qui ne sont pas des IME habituels)
Martin Smith
4

Vous pouvez le faire avec une case ... whenexpression:

mysql> select * from genderswap;
+--------+
| gender |
+--------+
| F      |
| F      |
| M      |
| M      |
| M      |
| M      |
| M      |
+--------+
7 rows in set (0.00 sec)

mysql> 
mysql> UPDATE genderswap SET gender = case 
    ->                                when gender='M' then 'F' 
    ->                                when gender='F' then 'M'
    ->                                end
    -> WHERE gender IN ('M', 'F');
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7  Changed: 7  Warnings: 0

mysql> 
mysql> select * from genderswap;
+--------+
| gender |
+--------+
| M      |
| M      |
| F      |
| F      |
| F      |
| F      |
| F      |
+--------+
7 rows in set (0.00 sec)

mysql> 
Philᵀᴹ
la source
2

J'utiliserais une mise à jour avec une caseexpression.

DECLARE @Test TABLE
    (
      Name VARCHAR(100) NULL
    , Gender CHAR(1) NULL
    );

INSERT  INTO @Test
        ( Name, Gender )
VALUES  ( 'Jonathan', 'W' )
         ,
        ( 'Kelly', 'M' );

SELECT  Name
      , Gender
FROM    @Test;

UPDATE  @Test
SET     Gender = CASE WHEN Gender = 'M' THEN 'W'
                      ELSE 'M'
                 END;

SELECT  Name
      , Gender
FROM    @Test;
Jonathan Fite
la source
-1

Vous pouvez effectuer cette mise à jour à l'aide d'une caseexpression.

UPDATE names_table
   SET names_table.gender = ( CASE
                                  WHEN names_table.gender = 'M'
                                    THEN 'W'
                                  ELSE
                                      names_table.gender = 'M'
                              END)

Je suggère d'exécuter votre déclaration de mise à jour dans une transaction et d'ajouter une requête simple telle que:

SELECT n.gender, *
FROM names_table

afin de vérifier les résultats que vous obtiendrez. Effectuer la transaction avec un rollback et la passer à un commit lorsque vos résultats correspondent à ce que vous attendez.

agpoweredmg
la source