Cambiar valores en una columna con una declaración de actualización

12

Usted encuentra que un error en un sistema ha sido nombrar incorrectamente hombres (M) como mujeres (W) y viceversa en la base de datos. Las columnas solo permiten un carácter. Sin usar ninguna tabla temporal, escriba una consulta de actualización para resolver esto.

Esta pregunta se hizo en una entrevista reciente que tuve, y voy a entrar en más entrevistas que pueden tener preguntas similares, así que quería tener una idea de cómo manejar esto.

Seth Sí
fuente
66
¿Le pidieron que asumiera un producto de base de datos en particular? por ejemplo, MySQL, SQL Server, Oracle, PostgreSQL ...?
Paul White 9
¿Ha leído su sistema las nuevas pautas de la comunidad? : \
AER

Respuestas:

22

Desea usar una CASEexpresión de algún tipo.

En SQL Server, el código se vería así:

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

Editar: como se indica en los comentarios (y algunas de las otras respuestas), ELSE no es necesario si coloca una cláusula WHERE en la declaración.

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

Esto evita actualizaciones innecesarias. Lo importante en cualquier caso es recordar que hay otras opciones además de M & W (NULL, por ejemplo) y que no desea ingresar información errónea. Por ejemplo:

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

Esto reemplazaría cualquier NULL (u otros géneros posibles) como 'M' que sería incorrecto.


Un par de otras opciones serían

/*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' );

Y un mas conciso

/*For SQL Server 2012+*/
UPDATE TableName
SET    gender = IIF(gender = 'M', 'W', 'M')
WHERE  gender IN ( 'M', 'W' ); 
Kenneth Fisher
fuente
1
Puede reemplazar el IIF()con IF()y funcionaría en MySQL;)
ypercubeᵀᴹ
9

En Oracle, podría usar un CASO ya que las otras respuestas tienen:

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

También puedes usar un DECODE:

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

Para cambiar entre solo dos valores, también puede probar este truco, que no usa una CASEexpresión (suponiendo que Transact-SQL aquí):

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

Dependiendo del valor actual de Gender, ASCII(Gender)se cancelará uno ASCII('M')u otro ASCII('W'), dejando que el otro código sea transformado por la CHAR()función nuevamente al carácter correspondiente.

Sin embargo, lo dejo solo para comparar. Si bien esta opción puede tener un pretexto de elegancia, CASEpodría decirse que una solución que usa una expresión sería más legible y, por lo tanto, más fácil de mantener, y definitivamente sería más fácil expandirse a más de dos valores.

Andriy M
fuente
2
Esperemos que todos los My sean Wingresados ​​en mayúsculas para evitar que 7aparezcan inesperados o '-` en los resultados.
Martin Smith
@ MartinSmith: Muy buen punto. Si no fuera así, tendremos que reemplazar ASCII(Gender)con ASCII(UPPER(Gender)), que es menos elegante, aunque no mucho.
Andriy M
@ MartinSmith, si hay minúsculas, ¿no serán rechazadas por la WHEREcláusula?
ypercubeᵀᴹ
1
@ YperSillyCubeᵀᴹ - Solo en caso de intercalaciones sensibles (que no son ese IME habitual)
Martin Smith
4

Puedes hacerlo con una case ... whenexpresión:

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ᵀᴹ
fuente
2

Usaría una actualización con una caseexpresión.

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
fuente
-1

Puede realizar esta actualización usando una caseexpresión.

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

Sugeriría ejecutar su declaración de actualización dentro de una transacción y agregar una consulta simple como:

SELECT n.gender, *
FROM names_table

para verificar los resultados que obtendrás. Realice la transacción con una reversión y cambie a una confirmación cuando sus resultados se alineen con lo que espera.

mgpoder
fuente