Konkrétní obtížnost zde:Dotazy s jednou nebo více agregačními funkcemi v SELECT seznam a žádný GROUP BY klauzule vytvoří přesně jeden řádek, i když žádný řádek nebyl nalezen v podkladové tabulce.
V WHERE nemůžete nic dělat klauzule k potlačení tohoto řádku. Takový řádek musíte potom vyloučit , tj. v HAVING klauzuli nebo ve vnějším dotazu.
Podle dokumentace:
Pokud dotaz obsahuje volání agregovaných funkcí, ale žádné
GROUP BYklauzule, stále dochází k seskupování:výsledkem je jeden řádek skupiny (nebo možná norows vůbec, pokud je pak jeden řádek odstraněn pomocíHAVING). Totéž platí, pokud obsahujeHAVINGklauzule, a to i bez volání agregačních funkcí neboGROUP BYdoložka.
Je třeba poznamenat, že přidání GROUP BY klauzule pouze s konstantním výrazem (která je jinak zcela nesmyslná!) funguje také. Viz příklad níže. Ale raději bych ten trik nepoužíval, i když je krátký, levný a jednoduchý, protože je stěží zřejmé, co dělá.
Následující dotaz vyžaduje pouze skenování jedné tabulky a vrátí 7 nejlepších kategorií seřazených podle počtu. Pokud (a pouze pokud ) existuje více kategorií, zbytek je shrnut do 'Ostatní':
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
-
Pokud více kategorií může mít stejný počet na 7. / 8. místě, musíte přerušit remízu. V mém příkladu kategorie s menším
categoryidvyhrát takový závod. -
Závorky musí obsahovat
LIMITneboORDER BYklauzule k jednotlivé větviUNIONdotaz. -
Stačí se připojit k tabulce
categorypro 7 nejlepších kategorií. A v tomto scénáři je obecně levnější nejprve agregovat a připojit se později. Nepřipojujte se tedy k základnímu dotazu v CTE (společný tabulkový výraz) s názvemcte, připojte se pouze k prvnímuSELECTUNIONdotaz, je to levnější. -
Nejste si jisti, proč potřebujete
COALESCE. Pokud máte cizí klíč zcontents.categoryidnacategory.ida obacontents.categoryidacategory.namejsou definoványNOT NULL(jako by pravděpodobně měly být), pak to nepotřebujete.
Liché GROUP BY true
Tohle by taky fungovalo:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true; A dokonce mám o něco rychlejší plány dotazů. Ale je to poněkud zvláštní hack ...
SQL Fiddle předvedení všech.
Související odpověď s podrobnějším vysvětlením pro UNION ALL / LIMIT technika:
- Sečtěte výsledky několika dotazů a poté najděte 5 nejlepších v SQL