Et par vigtige punkter om brug af SQL:
- Du kan ikke bruge kolonnealiaser i WHERE-udtrykket, men det kan du i HAVING-udtrykket. Det er årsagen til den fejl, du fik.
- Du kan gøre din optælling bedre ved at bruge JOIN og GROUP BY end ved at bruge korrelerede underforespørgsler. Det vil være meget hurtigere.
- Brug HAVING-sætningen til at filtrere grupper.
Sådan ville jeg skrive denne forespørgsel:
SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;
Jeg er klar over, at denne forespørgsel kan springe JOIN
over med t1, som i Charles Bretanas løsning. Men jeg antager, at du måske ønsker, at forespørgslen skal inkludere nogle andre kolonner fra t1.
Re:spørgsmålet i kommentaren:
Forskellen er, at WHERE
klausul evalueres på rækker før GROUP BY
reducerer grupper til en enkelt række pr. gruppe. HAVING
klausul evalueres efter grupper er dannet. Så du kan for eksempel ikke ændre COUNT()
af en gruppe ved at bruge HAVING
; du kan kun ekskludere selve gruppen.
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;
I ovenstående forespørgsel, WHERE
filtre for rækker, der matcher en betingelse, og HAVING
filtre for grupper, der har mindst fem tæller.
Det punkt, der forårsager forvirring hos de fleste, er, når de ikke har en GROUP BY
klausul, så det ser ud som HAVING
og WHERE
er udskiftelige.
WHERE
evalueres før udtryk i valglisten. Dette er muligvis ikke indlysende, fordi SQL-syntaks sætter valglisten først. Så du kan spare en masse dyr beregning ved at bruge WHERE
for at begrænse rækker.
SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;
Hvis du bruger en forespørgsel som ovenstående, beregnes udtrykkene i valglisten for hver række , kun for at kassere de fleste resultater på grund af HAVING
tilstand. Forespørgslen nedenfor beregner dog kun udtrykket for enkelt række matcher WHERE
tilstand.
SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;
Så for at opsummere, køres forespørgsler af databasemotoren i henhold til en række trin:
- Generer sæt rækker fra tabeller, inklusive alle rækker, der er produceret af
JOIN
. - Vurder
WHERE
betingelser i forhold til sættet af rækker, frafiltrering af rækker, der ikke matcher. - Beregn udtryk i valglisten for hver i rækken.
- Anvend kolonnealiasser (bemærk, at dette er et separat trin, hvilket betyder, at du ikke kan bruge aliaser i udtryk i valglisten).
- Kondenser grupper til en enkelt række pr. gruppe i henhold til
GROUP BY
klausul. - Vurder
HAVING
betingelser mod grupper, frafiltrering af grupper, der ikke matcher. - Sortér resultatet i henhold til
ORDER BY
klausul.