MySQL вложенный SELECT в UPDATE той же таблицы - PullRequest
11 голосов
/ 27 мая 2009

По сути, мне нужно сделать что-то вроде этого ... это просто пример ... но синтаксис первого запроса не работает в MySQL

update people set prize = '' 
where prize = 'Gold' and class = (select class from people where id = person_id);
update people set prize = 'Gold' where id = <id>;

Золотой приз в любом классе может получить только один человек. Я знаю только person_id человека, получившего Золотой приз.

Я пытаюсь убрать всех предыдущих обладателей золотых призов того же класса, что и person_id в первом запросе. Затем установите нового Золотого победителя во втором.

Я считаю, что мне нужно использовать какой-то тип внутреннего соединения, но я не уверен на 100% в этом.

Что было бы еще умнее, если бы я мог сделать все за один запрос!

Кто-нибудь может дать совет?

Спасибо:)

Ответы [ 5 ]

10 голосов
/ 27 мая 2009

Не всегда лучше делать сложные обновления в одном запросе SQL. Фактически, может быть более эффективно выполнить два простых запроса. Поэтому обязательно сравните оба решения.

MySQL поддерживает расширение синтаксиса UPDATE для многостолового обновления. Вы можете выполнить JOIN как часть обновления вместо использования подзапросов.

Затем вы можете использовать функцию IF() (или CASE), чтобы условно изменить значение prize на разные значения.

Так что, если вам абсолютно необходимо использовать один запрос, попробуйте что-то вроде этого:

UPDATE people p1 JOIN people p2 
  ON (p1.class = p2.class AND p2.id = <person_id>)
SET prize = IF(p1.id = <person_id>, 'Gold', '')
WHERE p1.id = <person_id> OR p1.prize = 'Gold';

Или эта альтернатива:

UPDATE people p1 JOIN people p2 
  ON (p1.class = p2.class AND p2.id = <person_id>)
SET p1.prize = CASE 
  WHEN p1.id = <person_id> THEN 'Gold'
  WHEN p1.prize = 'Gold' THEN ''
  ELSE p1.prize -- other cases are left as is
 END CASE;
7 голосов
/ 27 мая 2009
UPDATE people
SET    prize = CASE WHEN id = @lucky THEN 'Gold' ELSE 'Silver' END
WHERE  class = (
       SELECT  class
       FROM    people
       WHERE   id = @lucky
       )

Это даст всем пользователям приз Silver, кроме @lucky, получившего Gold.

.

Если вам нужно только обновить @lucky и экс-чемпиона, введите следующее:

UPDATE people
SET    prize = CASE WHEN id = @lucky THEN 'Gold' ELSE 'Silver' END
WHERE  id = @lucky
       OR (class, prize) =
       (
       SELECT  class, 'Gold'
       FROM    people
       WHERE   id = @lucky
       )
1 голос
/ 27 мая 2009

Если после одного утверждения вы могли бы использовать оператор CASE? Не используется MySQL, но что-то вроде:

UPDATE people
SET prize = CASE
              WHEN 'Gold' AND id != @newid THEN ''
              WHEN '' AND id = @newid THEN 'Gold'
            END 
WHERE class = ( 
                SELECT class 
                FROM people
                WHERE id = @newid 
              )
0 голосов
/ 27 мая 2009

Поскольку вы делаете два разных обновления, нет необходимости делать это в одном запросе. Если вы боитесь противоречивых данных из-за сбоя одного из двух запросов, вы можете использовать транзакции, и откат любого из двух запросов завершится неудачей.

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

0 голосов
/ 27 мая 2009

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

Затем вы можете вызвать эту хранимую процедуру в одну строку.

Я использую MS SQL здесь, но что-то похожее на:

CREATE PROC UpdatePrize
  @newid int

AS

UPDATE people
SET prize = '' 
WHERE prize = 'Gold'
AND class = ( SELECT class 
              FROM people
              WHERE id = @newid )

UPDATE people
SET prize = 'Gold'
WHERE id = @newid

GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...