PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Dapatkan n kategori yang dikelompokkan dan jumlahkan yang lain menjadi satu

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 dengan HAVING ). Hal yang sama berlaku jika berisi HAVING klausa, bahkan tanpa panggilan fungsi agregat atau GROUP 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 atau ORDER BY klausa ke kaki individu dari UNION 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) bernama cte , hanya bergabung di SELECT first pertama dari UNION kueri, itu lebih murah.

  • Tidak yakin mengapa Anda memerlukan COALESCE . Jika Anda memiliki kunci asing dari contents.categoryid ke category.id dan keduanya contents.categoryid dan category.name didefinisikan NOT 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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Berfungsi untuk mengembalikan kumpulan kolom dinamis untuk tabel yang diberikan

  2. Mengapa SELECT tanpa kolom valid

  3. Isolasi Transaksi di PostgreSQL

  4. Menginstal driver PDO untuk PostgreSQL di Mac (menggunakan Zend untuk Eclipse)

  5. Ubah nilai awal Django AutoField