Переключение значений в столбце с одним оператором обновления

12

Вы обнаружите, что ошибка в системе неправильно называет мужчин (M) женщинами (W) и наоборот в базе данных. Столбцы допускают только один символ. Без использования временных таблиц напишите один запрос на обновление, чтобы решить эту проблему.

Этот вопрос был задан на одном из моих недавних интервью, и я собираюсь поговорить с другими, у которых могут быть похожие вопросы, поэтому я хотел понять, как с этим справиться.

SethYes
источник
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');

Вы также можете использовать ДЕКОД:

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)
Martin Smith
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> 
Philᵀᴹ
источник
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

чтобы проверить результаты, которые вы получите. Выполнение транзакции с откатом и переключение на коммит, когда ваши результаты совпадают с ожидаемыми.

agpoweredmg
источник