Перемикання значень у стовпці з одним оператором оновлення


12

Ви виявляєте, що помилка в системі неправильно називає чоловіків (M) жінками (W) і навпаки в базі даних. У стовпцях розміщено лише один символ. Не використовуючи жодних темп-таблиць, напишіть один запит на оновлення, щоб вирішити цю проблему.

Це запитання було задано на моєму недавньому інтерв'ю, і я берусь на більше інтерв'ю, у яких можуть бути подібні запитання, тому я хотів отримати уявлення про те, як з цим впоратися.


6
Вас просили припустити конкретний продукт бази даних? наприклад, MySQL, SQL Server, Oracle, PostgreSQL ...?
Пол Білий 9

Чи читала ваша система нові правила спільноти? : \
AER

Відповіді:


23

Ви хочете використовувати CASEвираз певного типу.

У SQL Server код виглядатиме так:

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

Редагувати: Як зазначено в коментарях (та деяких інших відповідях), ELSE не потрібен, якщо ви додаєте до цього пункту пункт WHERE.

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

Це дозволяє уникнути зайвих оновлень. У будь-якому випадку важливо пам’ятати, що є інші варіанти, крім M&W (наприклад, NULL), і ви не хочете вводити помилкову інформацію. Наприклад:

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

Це замінить будь-які NULL (або інші можливі статі) як "M", що було б невірно.


Ще пару варіантів

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

І більш лаконічний

/*For SQL Server 2012+*/
UPDATE TableName
SET    gender = IIF(gender = 'M', 'W', 'M')
WHERE  gender IN ( 'M', 'W' ); 

1
Ви могли б замінити IIF()з IF()і вона буде працювати в MySQL;)
ypercubeᵀᴹ

9

В Oracle ви можете використовувати CASE, як і інші відповіді:

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

Ви також можете використовувати DECODE:

UPDATE TableName SET gender = DECODE(gender,'M','W','W','M')
WHERE gender in ('M','W');

5

Для перемикання між лише двома значеннями ви також можете спробувати цей трюк, який не використовує CASEвираз (припускаючи Transact-SQL тут):

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

Залежно від поточного значення Gender, ASCII(Gender)скасує ASCII('M')або ASCII('W'), залишивши інший код, який буде перетворений CHAR()функцією назад у відповідний символ.

Я залишаю це лише для порівняння. Незважаючи на те, що цей варіант може мати витонченість елегантності до нього, рішення, що використовує CASEвираз, може бути, читабельніше і, таким чином, легше підтримувати, і, безумовно, було б легше розширитись до більш ніж двох значень.


2
Будемо сподіватися, що всі Mі Wбули введені у верхньому регістрі, щоб уникнути несподіваного 7або `-` появи в результатах.
Мартін Сміт

@MartinSmith: Дуже добре. Якби вони не були, ми повинні замінити ASCII(Gender)з ASCII(UPPER(Gender)), що менш елегантно, хоча і не багато.
Андрій М

@MartinSmith, якщо m і w є малі регістри, вони не будуть відхилені цим WHEREпунктом?
ypercubeᵀᴹ

1
@ YperSillyCubeᵀᴹ - Лише у випадку делікатного порівняння (яке не є звичайним IME)
Мартін Сміт

4

Ви можете це зробити з case ... whenвиразом:

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> 

2

Я б використав оновлення з caseвиразом.

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;

-1

Ви можете виконати це оновлення за допомогою caseвиразу.

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

Я б запропонував запустити свою операцію оновлення в межах транзакції та додати простий запит, наприклад:

SELECT n.gender, *
FROM names_table

щоб перевірити результати, які ви отримаєте. Виконання транзакції з відкатом і переключення її на зобов'язання, коли ваші результати узгоджуються з тим, що ви очікуєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.