La difficoltà specifica qui:query con una o più funzioni aggregate in SELECT list e nessun GROUP BY La clausola produce esattamente una riga, anche se non viene trovata alcuna riga nella tabella sottostante.
Non c'è niente che puoi fare in WHERE clausola per sopprimere quella riga. Devi escludere tale riga dopo il fatto , cioè nel HAVING clausola o in una query esterna.
Per documentazione:
Se una query contiene chiamate di funzioni aggregate, ma non GROUP BY clausola, il raggruppamento si verifica ancora:il risultato è una singola riga di gruppo (o forse nessuna riga, se la singola riga viene poi eliminata da HAVING ). Lo stesso vale se contiene un HAVING clausola, anche senza chiamate aggregatefunction o GROUP BY clausola.
Va notato che l'aggiunta di un GROUP BY Anche la clausola con solo un'espressione costante (che altrimenti sarebbe completamente inutile!) funziona. Vedi esempio sotto. Ma preferirei non usare quel trucco, anche se è breve, economico e semplice, perché non è affatto ovvio cosa faccia.
La query seguente richiede solo una analisi di una singola tabella e restituisce le prime 7 categorie ordinate per conteggio. Se (e solo se ) ci sono più categorie, il resto è riassunto in 'Altri':
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
-
Devi rompere i pareggi se più categorie possono avere lo stesso conteggio nel 7°/8° grado. Nel mio esempio, le categorie con il
categoryidpiù piccolo vincere una gara del genere. -
Le parentesi sono necessarie per includere un
LIMIToORDER BYclausola a una singola gamba di unaUNIONinterrogazione. -
Devi solo iscriverti alla tabella
categoryper le prime 7 categorie. Ed è generalmente più economico aggregare prima e unirsi successivamente in questo scenario. Quindi non unirti alla query di base nella CTE (espressione di tabella comune) denominatacte, partecipa solo al primoSELECTdellaUNIONquery, è più economico. -
Non sono sicuro del motivo per cui hai bisogno del
COALESCE. Se disponi di una chiave esterna dacontents.categoryidacategory.ided entrambicontents.categoryidecategory.namesono definitiNOT NULL(come probabilmente dovrebbero essere), allora non ne hai bisogno.
Lo dispari GROUP BY true
Funzionerebbe anche questo:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true; E ottengo anche piani di query leggermente più veloci. Ma è un trucco piuttosto strano...
SQL Fiddle dimostrando tutto.
Risposta correlata con ulteriori spiegazioni per UNION ALL / LIMIT tecnica:
- Somma i risultati di alcune query e poi trova le prime 5 in SQL