2012-07-21 17 views
42

Kann jemand sehen, was ist falsch mit der unten stehenden Abfrage?mysql Update-Abfrage mit Unterabfrage

Wenn ich es laufen erhalte ich:

# 1064 - Sie haben einen Fehler in Ihrer SQL-Syntax; Sie in die Bedienungsanleitung zu Ihrer MySQL-Server-Version für die richtige Syntax entspricht verwenden in der Nähe von ‚ein, wo a.CompetitionID = Competition.CompetitionID‘ in Zeile 8

Update Competition 
Set Competition.NumberOfTeams = 
(
SELECT count(*) as NumberOfTeams 
FROM PicksPoints 
where UserCompetitionID is not NULL 
group by CompetitionID 
) a 
where a.CompetitionID = Competition.CompetitionID 

Antwort

113

Das Hauptproblem ist, dass die innere Abfrage kann nicht sich auf Ihre where-Klausel in der äußeren update-Anweisung beziehen, da der Where-Filter zuerst auf die Tabelle angewendet wird, die gerade aktualisiert wird, bevor die innere Unterabfrage ausgeführt wird. Der typische Umgang mit einer solchen Situation ist ein multi-table update.

Update 
    Competition as C 
    inner join (
    select CompetitionId, count(*) as NumberOfTeams 
    from PicksPoints as p 
    where UserCompetitionID is not NULL 
    group by CompetitionID 
) as A on C.CompetitionID = A.CompetitionID 
set C.NumberOfTeams = A.NumberOfTeams 

Demo: http://www.sqlfiddle.com/#!2/a74f3/1

+1

Vielen Dank, das hat den Trick :) Schätzen Sie auch die Erklärung, Prost! – user1542043

+0

Die Erklärung machte dies zu einer wirklich guten Antwort. –

15

Danke, ich habe nicht die Idee eines UPDATE mit INNER JOIN.

In der ursprünglichen Abfrage war der Fehler, die Unterabfrage zu benennen, die einen Wert zurückgeben muss und daher nicht Alias ​​sein kann.

UPDATE Competition 
SET Competition.NumberOfTeams = 
(SELECT count(*) -- no column alias 
    FROM PicksPoints 
    WHERE UserCompetitionID is not NULL 
    -- put the join condition INSIDE the subquery : 
    AND CompetitionID = Competition.CompetitionID 
    group by CompetitionID 
) -- no table alias 

sollte den Trick für jede Aufzeichnung des Wettbewerbs tun.

Zu bemerken:

Der Effekt nicht genau die gleiche wie die Abfrage von mellamokb vorgeschlagen ist, die nicht Wettbewerb Aufzeichnungen ohne entsprechende Pickpoints aktualisieren.

Seit SELECT id, COUNT(*) GROUP BY id wird nur für bestehende Werte von ids zählen,

während ein SELECT COUNT(*) immer einen Wert zurück, wobei 0, wenn keine Datensätze ausgewählt sind.

Dies kann oder kann kein Problem für Sie sein.

0-aware Version von mellamokb Abfrage wäre:

Update Competition as C 
LEFT join (
    select CompetitionId, count(*) as NumberOfTeams 
    from PicksPoints as p 
    where UserCompetitionID is not NULL 
    group by CompetitionID 
) as A on C.CompetitionID = A.CompetitionID 
set C.NumberOfTeams = IFNULL(A.NumberOfTeams, 0) 

Mit anderen Worten, wenn keine entsprechenden Pickpoints zu finden sind, stellen Competition.NumberOfTeams auf Null.

4

Für Ungeduldige:

UPDATE target AS t 
INNER JOIN (
    SELECT s.id, COUNT(*) AS count 
    FROM source_grouped AS s 
    -- WHERE s.custom_condition IS (true) 
    GROUP BY s.id 
) AS aggregate ON aggregate.id = target.id 
SET t.count = aggregate.count 

Die @mellamokb ‚s Antwort ist, wie oben beschrieben, auf den max reduziert.