Werte in einer Spalte mit einer Update-Anweisung wechseln

12

Sie stellen fest, dass ein Fehler in einem System dazu geführt hat, dass Männer (M) fälschlicherweise als Frauen (W) benannt wurden und umgekehrt in der Datenbank. Die Spalten erlauben nur ein Zeichen. Schreiben Sie ohne Verwendung von temporären Tabellen eine Aktualisierungsabfrage, um dies zu beheben.

Diese Frage wurde kürzlich bei einem Interview gestellt, das ich hatte, und ich gehe auf weitere Interviews ein, die möglicherweise ähnliche Fragen haben. Daher wollte ich eine Vorstellung davon bekommen, wie ich damit umgehen soll.

SethJa
quelle
6
Wurden Sie gebeten, ein bestimmtes Datenbankprodukt anzunehmen? zB MySQL, SQL Server, Oracle, PostgreSQL ...?
Paul White 9
Hat Ihr System die neuen Community-Richtlinien gelesen? : \
VRE

Antworten:

22

Sie möchten einen CASEAusdruck eines Typs verwenden.

In SQL Server würde der Code folgendermaßen aussehen:

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

Bearbeiten: Wie in den Kommentaren (und einigen anderen Antworten) angegeben, ist ELSE nicht erforderlich, wenn Sie eine WHERE-Klausel in die Anweisung einfügen.

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

Dies vermeidet unnötige Updates. In beiden Fällen ist es wichtig, sich daran zu erinnern, dass es andere Optionen als M & W gibt (z. B. NULL) und Sie keine falschen Informationen eingeben möchten. Beispielsweise:

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

Dies würde alle NULL-Werte (oder andere mögliche Geschlechter) als 'M' ersetzen, was falsch wäre.


Ein paar andere Optionen wären

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

Und eine prägnantere

/*For SQL Server 2012+*/
UPDATE TableName
SET    gender = IIF(gender = 'M', 'W', 'M')
WHERE  gender IN ( 'M', 'W' ); 
Kenneth Fisher
quelle
1
Sie könnten die ersetzen IIF()mit IF()und es würde in MySQL arbeiten;)
ypercubeᵀᴹ
9

In Oracle können Sie einen CASE verwenden, wie die anderen Antworten lauten:

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

Sie können auch einen DECODE verwenden:

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

Um zwischen nur zwei Werten zu wechseln, können Sie auch diesen Trick ausprobieren, bei dem kein CASEAusdruck verwendet wird (hier wird Transact-SQL vorausgesetzt):

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

Je nach dem aktuellen Wert Gender, ASCII(Gender)wird zunichte machen entweder ASCII('M')oder ASCII('W'), den anderen Code verlassen durch die zu transformierendenCHAR() Funktion zurück in den entsprechenden Zeichen.

Ich lasse dies jedoch nur zum Vergleich. Während diese Option einen Anspruch auf Eleganz hat, wäre eine Lösung, die einen CASEAusdruck verwendet, wahrscheinlich besser lesbar und daher leichter zu pflegen, und es wäre definitiv einfacher, sie auf mehr als zwei Werte zu erweitern.

Andriy M.
quelle
2
Hoffen wir, dass alle Mund Win Großbuchstaben eingegeben wurden, um zu vermeiden, dass unerwartete 7oder `-` in den Ergebnissen erscheinen.
Martin Smith
@ MartinSmith: Sehr guter Punkt. Wenn sie es nicht waren, werden wir ersetzen müssen ASCII(Gender)mit ASCII(UPPER(Gender)), was weniger elegant ist, wenn auch nicht viel.
Andriy M
@MartinSmith Wenn es m und w in Kleinbuchstaben gibt, werden sie dann nicht von der WHEREKlausel abgelehnt ?
Ypercubeᵀᴹ
1
@ YperSillyCubeᵀᴹ - Nur für den Fall, dass sensible Kollatierungen (die nicht das übliche IME sind)
Martin Smith
4

Sie können es mit einem case ... whenAusdruck tun :

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

Ich würde ein Update mit einem caseAusdruck verwenden.

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

Sie können dieses Update mit einem caseAusdruck durchführen.

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

Ich würde vorschlagen, Ihre Update-Anweisung innerhalb einer Transaktion auszuführen und eine einfache Abfrage hinzuzufügen, z.

SELECT n.gender, *
FROM names_table

um die Ergebnisse zu überprüfen, die Sie erhalten. Durchführen der Transaktion mit einem Rollback und Umschalten auf ein Commit, wenn Ihre Ergebnisse mit den Erwartungen übereinstimmen.

agpoweredmg
quelle