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
categoryid
wygraj taki wyścig. -
Nawiasy muszą zawierać
LIMIT
lubORDER BY
klauzula do pojedynczego odgałęzieniaUNION
zapytanie. -
Musisz tylko dołączyć do tabeli
category
dla 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 pierwszegoSELECT
UNION
zapytanie, to jest tańsze. -
Nie wiem, dlaczego potrzebujesz
COALESCE
. Jeśli masz klucz obcy zcontents.categoryid
docategory.id
i obacontents.categoryid
icategory.name
są 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