Alternando valores em uma coluna com uma instrução de atualização

12

Você descobre que um erro em um sistema foi nomear incorretamente homens (M) como mulheres (W) e vice-versa no banco de dados. As colunas permitem apenas um caractere. Sem usar nenhuma tabela temporária, escreva uma consulta de atualização para resolver isso.

Essa pergunta foi feita em uma entrevista recente que eu tive, e eu vou para mais entrevistas que podem ter perguntas semelhantes, então eu queria ter uma idéia de como lidar com isso.

Sim
fonte
6
Você foi solicitado a assumir um determinado produto de banco de dados? por exemplo, MySQL, SQL Server, Oracle, PostgreSQL ...?
Paul White 9
Seu sistema leu as novas diretrizes da comunidade? : \
AER

Respostas:

22

Você deseja usar uma CASEexpressão de algum tipo.

No SQL Server, o código ficaria assim:

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

Editar: Conforme declarado nos comentários (e em algumas das outras respostas), o ELSE não é necessário se você colocar uma cláusula WHERE na declaração.

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

Isso evita atualizações desnecessárias. O importante em ambos os casos é lembrar que existem outras opções além de M&W (NULL por exemplo) e você não deseja inserir informações equivocadas. Por exemplo:

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

Isso substituiria quaisquer NULLs (ou outros gêneros possíveis) como 'M' que estivessem incorretos.


Algumas outras opções seriam

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

E um mais conciso

/*For SQL Server 2012+*/
UPDATE TableName
SET    gender = IIF(gender = 'M', 'W', 'M')
WHERE  gender IN ( 'M', 'W' ); 
Kenneth Fisher
fonte
1
Você poderia substituir o IIF()com IF()e ele iria trabalhar em MySQL;)
ypercubeᵀᴹ
9

No Oracle, você pode usar um CASE, pois as outras respostas têm:

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

Você também pode usar um DECODE:

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

Para alternar entre apenas dois valores, você também pode tentar este truque, que não usa uma CASEexpressão (assumindo o Transact-SQL aqui):

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

Dependendo do valor atual de Gender, ASCII(Gender)cancelará ASCII('M')ou ASCII('W'), deixando o outro código a ser transformado pela CHAR()função de volta ao caractere correspondente.

Estou deixando isso apenas para comparação, no entanto. Embora essa opção possa ter uma aparência de elegância, CASEsem dúvida uma solução usando uma expressão seria mais legível e, portanto, mais fácil de manter, e seria definitivamente mais fácil expandir para mais de dois valores.

Andriy M
fonte
2
Vamos torcer para que todos os Me Wtenham sido digitados em maiúsculas para evitar que inesperados 7ou `-` apareçam nos resultados.
Martin Smith
@ MartinSmith: Muito bom ponto. Caso contrário, teremos que substituir ASCII(Gender)por ASCII(UPPER(Gender)), o que é menos elegante, embora não muito.
Andriy M
@MartinSmith, se houver minúsculas m e w, elas não serão rejeitadas pela WHEREcláusula?
precisa saber é o seguinte
1
@ YperSillyCubeᵀᴹ - apenas em caso agrupamentos sensíveis (que não são tão IME usual)
Martin Smith
4

Você pode fazer isso com uma case ... whenexpressão:

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

Eu usaria uma atualização com uma caseexpressão.

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

Você pode executar esta atualização usando uma caseexpressão.

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

Sugiro que você execute sua instrução de atualização em uma transação e adicione uma consulta simples, como:

SELECT n.gender, *
FROM names_table

para verificar os resultados que você obterá. Executar a transação com uma reversão e alterná-la para uma confirmação quando seus resultados estiverem alinhados com o que você espera.

agpoweredmg
fonte