2009-05-27 4 views
11

Zasadniczo muszę zrobić coś takiego .... to jest tylko przykład ... ale składnia pierwszej kwerendy nie działa w MySQLMySQL zagnieżdżone SELECT w aktualizacji samej tabeli

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>; 

Tylko jedna osoba może otrzymać nagrodę Złotą w dowolnej klasie. Znam tylko person_id osoby, która otrzymuje nagrodę Gold.

Próbuję odrzucić wszystkie poprzednie nagrody Gold zwycięzców w tej samej klasie co person_id w pierwszym zapytaniu. Następnie ustaw nowego zwycięzcę Złotego w drugim.

Uważam, że muszę użyć pewnego rodzaju sprzężenia wewnętrznego, ale nie jestem w 100% pewny.

Co byłoby jeszcze mądrzejsze, gdybym mógł wykonać całe zadanie w jednym zapytaniu!

Czy ktoś może udzielić porady?

Dzięki :)

Odpowiedz

7
UPDATE people 
SET prize = CASE WHEN id = @lucky THEN 'Gold' ELSE 'Silver' END 
WHERE class = (
     SELECT class 
     FROM people 
     WHERE id = @lucky 
     ) 

To zapewni wszystkim użytkownikom Silver nagrody, z wyjątkiem @lucky kto dostaje Gold.

Jeśli trzeba tylko zaktualizować @lucky i ex-mistrz, wydać następujące:

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 
     ) 
+0

nie zrobić tak samo jak pisał w pytaniu. Zmieniasz każdą nagrodę w klasie na "Złoto" lub "Srebro", podczas gdy powyższe zapytanie usuwa tylko nagrody "Złoto" i ustawia nowe. Przykład: co, jeśli jedna z osób ma cenę "brązową"? – VVS

+0

@ David Hympohl: Dobrze, możesz to zrobić, dodając "WHERE class =" Gold "lub id = @lucky" na końcu zapytania. – Andomar

+0

@David: zapytanie @ op ustawia nagrodę na "" dla każdej osoby w klasie. Właśnie zastąpiłem "" z "Srebrem" dla czytelności – Quassnoi

0

Można zdecydowanie utworzyć procedurę przechowywaną, która pobiera identyfikator nowego laureata jako argument.

Następnie można wywołać procedurę przechowywaną w jednym wierszu.

używam MS SQL tutaj, ale coś podobnego do:

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 
1

Jeśli jesteś po jednej instrukcji można użyć operatora przypadku? Nie używany MySQL, ale coś w tym stylu:

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

Co to jest PRZYCZYNA KIEDY "TEGO ma robić? Zawsze zwraca wartość false na moim serwerze. :) – Andomar

+0

Przepraszam, nie przetestowałem tego. Możesz użyć nagrody CASE KIEDY "Gold" TO .... lub jeśli potrzebujesz użyć wyrażenia CASE WHEN award = 'Gold' THEN ... WHEN prize = 'THEN ... –

0

Ponieważ robisz dwie różne aktualizacje, nie ma potrzeby robienia tego w jednym zapytaniu. Jeśli obawiasz się niespójnych danych, ponieważ jedno z tych dwóch zapytań może się nie udać, możesz użyć transakcji i wycofania któregokolwiek z tych dwóch zapytań.

Twoje aktualne zapytanie jest całkowicie czytelne i zrozumiałe, a zamieszczone w nim rozwiązania nie są łatwe do odczytania.

10

Nie zawsze najlepiej jest wykonywać złożone aktualizacje w jednym zapytaniu SQL. W rzeczywistości wydajniejsze może być uruchamianie dwóch prostych zapytań. Dlatego należy dokonać porównania obu rozwiązań.

MySQL obsługuje rozszerzenie do składni UPDATE dla aktualizacji wielostolikowych. Można wykonać JOIN jako część aktualizacji, zamiast używać podzapytań.

Następnie można użyć funkcji IF() (lub CASE), aby zmienić wartość prize na różne wartości warunkowo.

Więc jeśli absolutnie muszą korzystać z jednego zapytania, spróbuj coś takiego:

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'; 

albo to alternatywa:

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; 
+0

Czy to nie brąz właściciele nagród swoich medali? – Andomar

+0

@Andomar: Masz rację. W tej sprawie zredagowałem odpowiedź. –