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 BY
klauzule, 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 obsahujeHAVING
klauzule, a to i bez volání agregačních funkcí neboGROUP BY
dolož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
categoryid
vyhrát takový závod. -
Závorky musí obsahovat
LIMIT
neboORDER BY
klauzule k jednotlivé větviUNION
dotaz. -
Stačí se připojit k tabulce
category
pro 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ímuSELECT
UNION
dotaz, je to levnější. -
Nejste si jisti, proč potřebujete
COALESCE
. Pokud máte cizí klíč zcontents.categoryid
nacategory.id
a obacontents.categoryid
acategory.name
jsou 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