PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL - Fehler bei korrelierter Unterabfrage?

Einige wichtige Punkte zur Verwendung von SQL:

  • Sie können keine Spaltenaliase in der WHERE-Klausel verwenden, aber Sie können dies in der HAVING-Klausel tun. Das ist die Ursache für den Fehler, den Sie erhalten haben.
  • Sie können Ihre Zählung mit JOIN und GROUP BY besser durchführen als mit korrelierten Unterabfragen. Das geht viel schneller.
  • Verwenden Sie die HAVING-Klausel, um Gruppen zu filtern.

So würde ich diese Abfrage schreiben:

SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;

Mir ist klar, dass diese Abfrage den JOIN überspringen kann mit t1, wie in der Lösung von Charles Bretana. Aber ich nehme an, Sie möchten vielleicht, dass die Abfrage einige andere Spalten von t1 enthält.

Betreff:die Frage im Kommentar:

Der Unterschied besteht darin, dass der WHERE -Klausel wird für Zeilen vor GROUP BY ausgewertet reduziert Gruppen auf eine einzelne Zeile pro Gruppe. Das HAVING -Klausel wird ausgewertet, nachdem Gruppen gebildet wurden. Sie können also beispielsweise COUNT() nicht ändern einer Gruppe mit HAVING; Sie können nur die Gruppe selbst ausschließen.

SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;

In der obigen Abfrage WHERE filtert nach Zeilen, die einer Bedingung entsprechen, und HAVING filtert nach Gruppen, die mindestens fünf zählen.

Der Punkt, der die meisten Leute verwirrt, ist, wenn sie kein GROUP BY haben Klausel, so scheint es wie HAVING und WHERE sind austauschbar.

WHERE wird vor Ausdrücken in der Auswahlliste ausgewertet. Dies ist möglicherweise nicht offensichtlich, da die SQL-Syntax die Auswahlliste an die erste Stelle setzt. Sie können also eine Menge teurer Berechnungen sparen, indem Sie WHERE verwenden um Zeilen einzuschränken.

SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;

Wenn Sie eine Abfrage wie oben verwenden, werden die Ausdrücke in der Auswahlliste für jede Zeile berechnet , nur um die meisten Ergebnisse wegen HAVING zu verwerfen Bedingung. Die folgende Abfrage berechnet den Ausdruck jedoch nur für die einzelne Zeile passend zum WHERE Zustand.

SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;

Um es noch einmal zusammenzufassen:Abfragen werden von der Datenbank-Engine gemäß einer Reihe von Schritten ausgeführt:

  1. Zeilensatz aus Tabelle(n) generieren, einschließlich aller durch JOIN erzeugten Zeilen .
  2. Werte WHERE aus Bedingungen gegen den Satz von Zeilen, wobei Zeilen herausgefiltert werden, die nicht übereinstimmen.
  3. Berechnen Sie Ausdrücke in der Auswahlliste für jede in der Reihe von Zeilen.
  4. Spaltenaliase anwenden (beachten Sie, dass dies ein separater Schritt ist, was bedeutet, dass Sie keine Aliase in Ausdrücken in der Auswahlliste verwenden können).
  5. Verdichten Sie Gruppen gemäß GROUP BY zu einer einzigen Zeile pro Gruppe Klausel.
  6. Bewerten Sie HAVING Bedingungen gegen Gruppen, wobei Gruppen herausgefiltert werden, die nicht übereinstimmen.
  7. Ergebnis sortieren, nach ORDER BY Klausel.