PostgreSQL - Sub-Query-Fail-korreliert?
-
06-07-2019 - |
Frage
Ich habe eine Abfrage wie folgt:
SELECT t1.id,
(SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) as num_things
FROM t1
WHERE num_things = 5;
Das Ziel ist es, die ID aller Elemente zu erhalten, die 5-mal in der anderen Tabelle erscheinen. Allerdings habe ich diesen Fehler:
ERROR: column "num_things" does not exist
SQL state: 42703
Ich mache wahrscheinlich etwas albern hier, wie ich auf Datenbanken etwas neu bin. Gibt es eine Möglichkeit, diese Abfrage zu beheben, damit ich num_things
zugreifen kann? Oder, wenn nicht, gibt es eine andere Möglichkeit, dieses Ergebnis zu erreichen?
Lösung
Ich glaube, Sie nur Ihre Abfrage wie so umschreiben könnte:
SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) = 5;
Andere Tipps
Einige wichtige Punkte über SQL verwenden:
- Sie können nicht Spalte Aliase in der WHERE-Klausel verwenden, aber Sie können in der HAVING-Klausel. Das ist die Ursache für den Fehler Sie.
- Sie können besser Ihre Zählung tun mit einem JOIN und GROUP BY als durch korrelierte Unterabfragen verwenden. Es wird viel schneller sein.
- Verwenden Sie die HAVING-Klausel Gruppen zu filtern.
Hier ist die Art, wie ich diese Abfrage schreiben würde:
SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;
Ich weiß, diese Abfrage die JOIN
mit t1 überspringen kann, wie in Charles Bretana Lösung. Aber ich nehme an, Sie könnten die Abfrage einige andere Spalten von t1 aufgenommen werden sollen.
Re: die Frage im Kommentar:
Der Unterschied besteht darin, dass die WHERE
Klausel auf Zeilen ausgewertet wird, bevor GROUP BY
Gruppen zu einer einzelnen Zeile pro Gruppe reduziert. Die HAVING
Klausel wird ausgewertet nach Gruppen gebildet werden. So kann man zum Beispiel nicht, ändern Sie die COUNT()
einer Gruppe von HAVING
verwendet wird; Sie können nur die Gruppe ausschließen selbst.
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
Filter für Zeilen eine Bedingung erfüllen, und HAVING
Filter für Gruppen, die mindestens fünf Anzahl haben.
Der Punkt, den die meisten Menschen Verwirrung verursacht, ist, wenn sie nicht über eine GROUP BY
Klausel haben, so dass es scheint wie HAVING
und WHERE
sind austauschbar.
WHERE
wird, bevor Ausdrücke in der Auswahlliste ausgewertet. Dies kann nicht offensichtlich, da SQL-Syntax zuerst die Auswahlliste setzt. So können Sie eine Menge teuerer Berechnung sparen durch WHERE
mit Zeilen zu beschränken.
SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;
Wenn Sie eine Abfrage wie die oben verwenden, die Ausdrücke in der Auswahlliste berechnet für jede Zeile , nur die meisten Ergebnisse zu verwerfen, weil der HAVING
Zustand. Jedoch unterhalb der Abfrage berechnet den Ausdruck nur für die einreihige Anpassen der WHERE
Zustand.
SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;
So zu rekapitulieren, werden Abfragen, die von dem Datenbank-Engine laufen nach Reihe von Schritten:
- Erzeugen von Zeilen aus der Tabelle (n) festgelegt, einschließlich der Zeilen, die von
JOIN
hergestellt. -
WHERE
Bedingungen gegen den Satz von Zeilen auswerten, Zeilen herausgefiltert werden, die nicht übereinstimmen. - Compute Ausdrücke in Auswahlliste für jeden in der Menge von Zeilen.
- Spalte Aliase Nehmen (beachten Sie, das ein separater Schritt ist, was bedeutet, dass Sie keine Aliase in Ausdrücke in der Auswahlliste verwenden können).
- Condense Gruppen zu einer einzelnen Zeile pro Gruppe nach
GROUP BY
Klausel. - Ausrechnen
HAVING
Bedingungen gegen Gruppen, Gruppen Ausfiltern, die nicht übereinstimmen. - Ergebnis sortiert nach
ORDER BY
Klausel.
Alle anderen Vorschläge funktionieren würde, aber Ihre grundlegende Frage zu beantworten, wäre es ausreichend, schreiben
SELECT id From T2
Group By Id
Having Count(*) = 5
Ich mag, dass in PostgreSQL erwähnen, dass es keine Möglichkeit gibt, in having-Klausel aliased Spalte zu verwenden.
d.
SELECT usr_id AS my_id FROM Benutzer MIT my_id = 1
wird nicht funktionieren.
Ein weiteres Beispiel, das nicht zur Arbeit gehen wird:
SELECT su.usr_id AS my_id, COUNT (*) FROM AS val sys_user AS su GROUP BY su.usr_id HAVING val> = 1
Es wird der gleiche Fehler sein. Val Spalte ist nicht bekannt,
Im highliting weil Bill Karwin schrieb etwas nicht wirklich wahr für Postgres:
„Sie können nicht Spalte Aliase in der WHERE-Klausel verwenden, aber Sie können in der HAVING-Klausel. Das ist die Ursache für den Fehler, den Sie bekommen.“
try this
SELECT t1.id,
(SELECT COUNT(t2.id) as myCount
FROM t2
WHERE t2.id = t1.id and myCount=5
) as num_things
FROM t1