konkretna trudność tutaj:zapytania z co najmniej jedną funkcją agregującą w SELECT lista i nie GROUP BY klauzula tworzy dokładnie jeden wiersz, nawet jeśli nie znaleziono żadnego wiersza w tabeli poniżej.
Nie możesz nic zrobić w WHERE klauzula, aby pominąć ten wiersz. Musisz wykluczyć taki wiersz po fakcie , czyli w HAVING klauzuli lub w zewnętrznym zapytaniu.
Zgodnie z dokumentacją:
Jeśli zapytanie zawiera wywołania funkcji agregujących, ale nie GROUP BY klauzula,grupowanie nadal występuje:wynikiem jest pojedynczy wiersz grupy (lub być może w ogóle norows, jeśli pojedynczy wiersz zostanie następnie wyeliminowany przez HAVING ). To samo jest prawdziwe, jeśli zawiera HAVING klauzula, nawet bez wywołań funkcji agregujących lub GROUP BY klauzula.
Należy zauważyć, że dodanie GROUP BY klauzula zawierająca tylko wyrażenie stałe (które w przeciwnym razie jest całkowicie bezcelowe!) również działa. Zobacz przykład poniżej. Ale wolałbym nie używać tej sztuczki, nawet jeśli jest krótka, tania i prosta, ponieważ nie wiadomo, do czego służy.
Następujące zapytanie wymaga tylko skanowania pojedynczej tabeli i zwraca 7 najlepszych kategorii uporządkowanych według liczby. Jeśli (i tylko jeśli ) jest więcej kategorii, reszta jest podsumowana jako „Inne”:
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
-
Musisz zerwać remisy, jeśli wiele kategorii może mieć taką samą liczbę na 7 / 8 pozycji. W moim przykładzie kategorie z mniejszym
categoryidwygraj taki wyścig. -
Nawiasy muszą zawierać
LIMITlubORDER BYklauzula do pojedynczego odgałęzieniaUNIONzapytanie. -
Musisz tylko dołączyć do tabeli
categorydla 7 najlepszych kategorii. W tym scenariuszu generalnie taniej jest najpierw dokonać agregacji, a później dołączyć. Dlatego nie dołączaj do podstawowego zapytania w CTE (wspólne wyrażenie tabelowe) o nazwiecte, dołącz tylko do pierwszegoSELECTUNIONzapytanie, to jest tańsze. -
Nie wiem, dlaczego potrzebujesz
COALESCE. Jeśli masz klucz obcy zcontents.categoryiddocategory.idi obacontents.categoryidicategory.namesą zdefiniowaneNOT NULL(tak jak prawdopodobnie powinny być), to nie jest to potrzebne.
Nieparzyste GROUP BY true
To też by zadziałało:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true; Dostaję nawet nieco szybsze plany zapytań. Ale to dość dziwny hack...
Skrzypce SQL demonstrując wszystko.
Powiązana odpowiedź z dodatkowym wyjaśnieniem dla UNION ALL / LIMIT technika:
- Podsumuj wyniki kilku zapytań, a następnie znajdź 5 najlepszych w SQL