2009-05-27 15 views
11

Im Wesentlichen, so etwas zu tun, ich brauche .... Dies ist nur ein Beispiel ... aber die Syntax der ersten Abfrage funktioniert nicht in MySQLmysql SELECT in UPDATE von derselben Tabelle verschachtelt

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

Nur eine Person kann den Goldpreis in jeder Klasse haben. Ich kenne nur die person_id der Person, die den Goldpreis erhält.

Ich versuche, alle vorherigen Gold-Preisträger in der gleichen Klasse wie person_id in der ersten Abfrage auszublenden. Setzen Sie dann den neuen Gold-Gewinner in der zweiten.

Ich glaube, ich muss eine Art von inneren Join verwenden, aber ich bin mir nicht 100% sicher.

Was wäre noch schlauer, wenn ich das ganze in einer Abfrage tun könnte!

Kann mir jemand einen Rat geben?

Thanks :)

Antwort

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

Diese alle Benutzer mit einem Silver Preis gewähren, mit Ausnahme der @lucky derjenige, der Gold bekommt.

Wenn Sie nur die @lucky und der Ex-Champion zu aktualisieren, geben Sie den folgenden:

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

Das ist nicht das gleiche tut wie in der Frage geschrieben. Sie überschreiben jeden Preis innerhalb einer Klasse entweder mit "Gold" oder "Silber", während die obige Abfrage nur die "Gold" -Preise entfernt und einen neuen setzt. Beispiel: Was wäre, wenn einer der Leute einen "Bronze" -Preis hätte? – VVS

+0

@David Hympohl: Guter Punkt, Sie könnten das tun, indem Sie "WHERE class = 'Gold' oder id = @lucky" an das Ende der Abfrage anhängen. – Andomar

+0

@David: Die Abfrage von @ op setzt den Preis auf '' für jede Person innerhalb der Klasse. Ich habe gerade ein '' mit 'Silber' ersetzt, um die Lesbarkeit zu verbessern. – Quassnoi

0

Sie könnte auf jeden Fall eine gespeicherte Prozedur erstellen, die die ID des neuen Preisträger als Argument.

Dann können Sie diese gespeicherte Prozedur in einer Zeile aufrufen.

Ich verwende hier MS SQL, aber etwas ähnliches wie:

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

Wenn Sie nach einer einzigen Anweisung sind Sie den CASE-Operator verwenden könnten? Nicht verwendet MySQL, aber etwas wie:

+0

Was ist CASE WANN '' DANN? Gibt auf meinem Server immer false zurück. :) – Andomar

+0

ah Entschuldigung, hatte es nicht getestet. Sie können CASE-Preis WENN 'Gold' DANN .... oder wenn Sie einen Ausdruck CASE WHEN verwenden müssen, wenn Preis = 'Gold' DANN ... WANN Preis = '' DANN .... –

0

Da Sie zwei verschiedene Updates tun, gibt es keine Notwendigkeit, es in einer Abfrage zu tun. Wenn Sie Angst vor inkonsistenten Daten haben, weil eine der beiden Abfragen fehlschlägt, können Sie Transaktionen verwenden, und das Rollback einer der beiden Abfragen schlägt fehl.

Ihre aktuelle Abfrage ist vollständig lesbar und verständlich, während die veröffentlichten Lösungen weit davon entfernt sind, leicht lesbar zu sein.

10

Es ist nicht immer das Beste, komplexe Aktualisierungen in einer einzigen SQL-Abfrage durchzuführen. In der Tat könnte es effizienter sein, zwei einfache Abfragen auszuführen. Achten Sie also darauf, beide Lösungen zu benchmarken.

MySQL unterstützt eine Erweiterung auf UPDATE Syntax für Multi-Tabellen-Update. Sie können eine JOIN als Teil des Updates ausführen, anstatt Unterabfragen zu verwenden.

Dann können Sie die Funktion IF() (oder CASE) verwenden, um den Wert prize bedingt in andere Werte zu ändern.

Wenn Sie also unbedingt eine einzelne Abfrage verwenden müssen, versuchen, etwas wie folgt aus:

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

Oder diese Alternative:

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

Würde das nicht Bronze zu berauben Preisbesitzer ihrer Medaille? – Andomar

+0

@Andomar: Du hast Recht. Ich habe die Antwort in diesem Sinne bearbeitet. –

Verwandte Themen