Kesulitan khusus di sini:Kueri dengan satu atau lebih fungsi agregat di SELECT
daftar dan tidak ada GROUP BY
klausa menghasilkan tepat satu baris, meskipun tidak ada baris yang ditemukan di tabel di bawahnya.
Tidak ada yang dapat Anda lakukan di WHERE
klausa untuk menekan baris itu. Anda harus mengecualikan baris seperti itu setelah fakta , yaitu di HAVING
klausa, atau dalam kueri luar.
Per dokumentasi:
Jika kueri berisi panggilan fungsi agregat, tetapi tidak ada
GROUP BY
klausa,pengelompokan masih terjadi:hasilnya adalah baris grup tunggal (atau mungkin norows sama sekali, jika baris tunggal kemudian dihilangkan denganHAVING
). Hal yang sama berlaku jika berisiHAVING
klausa, bahkan tanpa panggilan fungsi agregat atauGROUP BY
klausa.
Perlu dicatat bahwa menambahkan GROUP BY
klausa dengan hanya ekspresi konstan (yang sama sekali tidak ada gunanya!) juga berfungsi. Lihat contoh di bawah. Tapi saya lebih suka tidak menggunakan trik itu, meskipun pendek, murah dan sederhana, karena hampir tidak jelas fungsinya.
Kueri berikut hanya membutuhkan pemindaian tabel tunggal dan mengembalikan 7 kategori teratas yang diurutkan berdasarkan hitungan. Jika (dan hanya jika ) ada lebih banyak kategori, sisanya diringkas menjadi 'Lainnya':
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
-
Anda perlu memutuskan hubungan jika beberapa kategori dapat memiliki jumlah yang sama di peringkat ke-7 / ke-8. Dalam contoh saya, kategori dengan
categoryid
yang lebih kecil memenangkan perlombaan seperti itu. -
Tanda kurung diperlukan untuk menyertakan
LIMIT
atauORDER BY
klausa ke kaki individu dariUNION
kueri. -
Anda hanya perlu bergabung ke tabel
category
untuk 7 kategori teratas. Dan biasanya lebih murah untuk menggabungkan terlebih dahulu dan bergabung kemudian dalam skenario ini. Jadi jangan bergabung dalam kueri dasar di CTE (ekspresi tabel umum) bernamacte
, hanya bergabung diSELECT
first pertama dariUNION
kueri, itu lebih murah. -
Tidak yakin mengapa Anda memerlukan
COALESCE
. Jika Anda memiliki kunci asing daricontents.categoryid
kecategory.id
dan keduanyacontents.categoryid
dancategory.name
didefinisikanNOT NULL
(seperti yang seharusnya), maka Anda tidak membutuhkannya.
Aneh GROUP BY true
Ini juga akan berhasil:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true;
Dan saya bahkan mendapatkan paket kueri yang sedikit lebih cepat. Tapi ini peretasan yang agak aneh ...
SQL Fiddle mendemonstrasikan semuanya.
Jawaban terkait dengan penjelasan lebih lanjut untuk UNION ALL
/ LIMIT
teknik:
- Jumlah hasil dari beberapa kueri lalu temukan 5 teratas di SQL