Den specifikke sværhedsgrad her:Forespørgsler med en eller flere samlede funktioner i SELECT
liste og ingen GROUP BY
klausul producere nøjagtig én række, selvom ingen række er fundet i den underliggende tabel.
Der er intet du kan gøre i WHERE
klausul for at undertrykke den række. Du skal udelukke sådan en række efter kendsgerningen , dvs. i HAVING
klausul eller i en ydre forespørgsel.
Per dokumentation:
Hvis en forespørgsel indeholder samlede funktionskald, men ingen GROUP BY
klausul, gruppering forekommer stadig:resultatet er en enkelt grupperække (eller måske i det hele taget norows, hvis den enkelte række derefter elimineres ved HAVING
). Det samme gælder, hvis det indeholder en HAVING
klausul, selv uden aggregatfunktionskald eller GROUP BY
klausul.
Det skal bemærkes, at tilføjelse af en GROUP BY
klausul med kun et konstant udtryk (som ellers er fuldstændig meningsløst!) virker også. Se eksempel nedenfor. Men jeg vil helst ikke bruge det trick, selvom det er kort, billigt og enkelt, for det er næppe indlysende, hvad det gør.
Følgende forespørgsel kræver kun en enkelt tabelscanning og returnerer de 7 bedste kategorier sorteret efter antal. Hvis (og kun hvis ) der er flere kategorier, resten er opsummeret i 'Andre':
WITH cte AS (
SELECT categoryid, count(*) AS data
, row_number() OVER (ORDER BY count(*) DESC, categoryid) AS rn
FROM contents
GROUP BY 1
)
( -- parentheses required again
SELECT categoryid, COALESCE(ca.name, 'Unknown') AS label, data
FROM cte
LEFT JOIN category ca ON ca.id = cte.categoryid
WHERE rn <= 7
ORDER BY rn
)
UNION ALL
SELECT NULL, 'Others', sum(data)
FROM cte
WHERE rn > 7 -- only take the rest
HAVING count(*) > 0; -- only if there actually is a rest
-- or: HAVING sum(data) > 0
-
Du er nødt til at bryde båndene, hvis flere kategorier kan have det samme antal på tværs af 7./8. rang. I mit eksempel kategorier med det mindre
categoryid
vinde sådan et løb. -
Parentes er påkrævet for at inkludere en
LIMIT
ellerORDER BY
klausul til en individuel del af enUNION
forespørgsel. -
Du behøver kun at tilslutte dig tabellen
category
for de 7 bedste kategorier. Og det er generelt billigere at samle først og slutte sig til senere i dette scenarie. Så deltag ikke i basisforespørgslen i CTE (fælles tabeludtryk) ved navncte
, kun deltage i den førsteSELECT
afUNION
forespørgsel, det er billigere. -
Ikke sikker på, hvorfor du har brug for
COALESCE
. Hvis du har en fremmednøgle på plads fracontents.categoryid
tilcategory.id
og beggecontents.categoryid
ogcategory.name
er defineretNOT NULL
(som de nok burde være), så behøver du det ikke.
Den ulige GROUP BY true
Dette ville også virke:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true;
Og jeg får endda lidt hurtigere forespørgselsplaner. Men det er et ret mærkeligt hack ...
SQL Fiddle demonstrerer alle.
Relateret svar med mere forklaring til UNION ALL
/ LIMIT
teknik:
- Summer resultaterne af nogle få forespørgsler, og find derefter top 5 i SQL