MySQL: Ungültige Verwendung der Gruppenfunktion

104

Ich benutze MySQL. Hier ist mein Schema:

Lieferanten ( sid: integer , sname: string, address string)

Teile ( pid: integer , pname: string, color: string)

Katalog ( sid: integer, pid: integer , cost: real)

(Primärschlüssel sind fett gedruckt)

Ich versuche, eine Abfrage zu schreiben, um alle Teile auszuwählen, die von mindestens zwei Lieferanten hergestellt werden:

-- Find the pids of parts supplied by at least two different suppliers.
SELECT c1.pid                      -- select the pid
FROM Catalog AS c1                 -- from the Catalog table
WHERE c1.pid IN (                  -- where that pid is in the set:
    SELECT c2.pid                  -- of pids
    FROM Catalog AS c2             -- from catalog
    WHERE c2.pid = c1.pid AND COUNT(c2.sid) >= 2 -- where there are at least two corresponding sids
);

Zunächst einmal, mache ich das überhaupt richtig?

Zweitens erhalte ich diesen Fehler:

1111 - Ungültige Verwendung der Gruppenfunktion

Was mache ich falsch?

Nick Heiner
quelle

Antworten:

173

Sie müssen verwenden HAVING, nicht WHERE.

Der Unterschied ist: Die WHEREKlausel filtert, welche Zeilen MySQL auswählt. Dann gruppiert MySQL die Zeilen und aggregiert die Zahlen für Ihre COUNTFunktion.

HAVINGist so WHERE, als ob es nur passiert, nachdem der COUNTWert berechnet wurde, so dass es wie erwartet funktioniert. Schreiben Sie Ihre Unterabfrage wie folgt um:

(                  -- where that pid is in the set:
SELECT c2.pid                  -- of pids
FROM Catalog AS c2             -- from catalog
WHERE c2.pid = c1.pid
HAVING COUNT(c2.sid) >= 2)
rjh
quelle
24
Auch wenn GROUP BY verwendet wird, sollte HAVING nach GROUP BY
Viacheslav
1
Außerdem muss GROUP BY vor HAVING sein ... Sollte Bandoleros Kommentar gelesen haben: D
Andrew
8

Erstens ist der Fehler darauf zurückzuführen, wo Sie die COUNTFunktion verwenden - Sie können keine Aggregat- (oder Gruppen-) Funktion in der WHEREKlausel verwenden.

Zweitens, anstatt eine Unterabfrage zu verwenden, verbinden Sie einfach die Tabelle mit sich selbst:

SELECT a.pid 
FROM Catalog as a LEFT JOIN Catalog as b USING( pid )
WHERE a.sid != b.sid
GROUP BY a.pid

Was meiner Meinung nach nur Zeilen zurückgeben sollte, in denen mindestens zwei Zeilen mit derselben existieren, pidaber mindestens 2 sids vorhanden sind. Um sicherzustellen, dass Sie nur eine Zeile pro Zeile zurückerhalten, pidhabe ich eine Gruppierungsklausel angewendet.

Mark Elliot
quelle
Ist es möglich, dass ich nicht einmal einen Join brauche? (Siehe meine aktualisierte Antwort, wo ich eine mögliche Lösung geliefert habe.)
Nick Heiner
@Rosarch, ich denke, Sie möchten COUNT(DISTINCT sid)in Ihrer aktualisierten Abfrage verwenden.
Mark Elliot
Müsste sidsowieso nicht immer verschieden sein, weil sidund pidzusammen einen Primärschlüssel für bilden Catalog?
Nick Heiner