Membuat Histogram dan Bucket Data di SQL
Blog/Tutorial SQL/Membuat Histogram dan Bucket Data di SQL

Membuat Histogram dan Bucket Data di SQL

BimaBima
·8 Agustus 2026·10 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Histogram di SQL dibuat dengan mengelompokkan nilai numerik ke dalam rentang atau bucket, lalu menghitung berapa baris yang jatuh di tiap bucket pakai COUNT dan GROUP BY. Cara paling portabel pakai CASE WHEN untuk bikin label rentang manual. Untuk bucket dengan lebar sama, FLOOR lebih ringkas. PostgreSQL punya WIDTH_BUCKET yang otomatis membagi rentang jadi sejumlah bucket. Bucket yang kosong perlu di-join dengan generate_series biar tetap muncul.

Histogram di SQL adalah cara ngelompokin nilai numerik ke dalam rentang, lalu ngitung berapa baris yang masuk tiap rentang. Rentang ini namanya bucket atau bin.

Gunanya buat lihat sebaran data. Berapa transaksi yang di bawah 25 ribu, berapa yang 25 sampai 50 ribu, berapa yang di atas 100 ribu. Rata-rata doang nggak nunjukin bentuk sebaran. Histogram nunjukin.

Di bawah ini aku bahas tiga cara bikin bucket: CASE WHEN yang jalan di semua database, FLOOR buat bucket lebar sama, dan WIDTH_BUCKET khusus PostgreSQL. Plus cara nampilin bucket kosong. Semua pakai dataset toko_berkah.

Apa itu histogram dan bucket di SQL?

Histogram di SQL adalah hasil query yang nampilin jumlah baris per rentang nilai. Tiap rentang disebut bucket. Query-nya kerja dengan cara nentuin baris masuk bucket mana, lalu GROUP BY bucket itu dan COUNT isinya. Hasilnya tabel dua kolom: label bucket dan jumlah. Beda sama chart, output SQL ini berupa angka, tapi tinggal ditempel ke bar chart buat jadi histogram visual.

Kalau kamu mau ukuran sebaran yang lebih ringkas kayak median atau kuartil, itu ada di Menghitung Median dan Percentile di SQL.

Cara bikin bucket pakai CASE WHEN

Cara paling portabel dan paling fleksibel. Kamu nentuin batas tiap bucket manual pakai CASE WHEN. Jalan di MySQL, PostgreSQL, SQL Server, SQLite.

SELECT
  CASE
    WHEN total < 25000 THEN '1. di bawah 25rb'
    WHEN total < 50000 THEN '2. 25rb-50rb'
    WHEN total < 100000 THEN '3. 50rb-100rb'
    ELSE '4. 100rb ke atas'
  END AS bucket,
  COUNT(*) AS jumlah
FROM transaksi
GROUP BY 1
ORDER BY 1;

CASE nentuin tiap transaksi masuk label mana. GROUP BY 1 ngelompokin berdasarkan kolom pertama (bucket-nya). COUNT ngitung isinya. Aku kasih nomor di depan label biar urutannya rapi waktu di-ORDER BY.

Kelebihan cara ini: bucket-nya nggak harus lebar sama. Kamu bisa bikin "0 sampai 25rb" lalu langsung "100rb ke atas" sesuai logika bisnis. Kelemahannya: kalau bucket-nya banyak, CASE-nya jadi panjang.

Cara bikin bucket lebar sama pakai FLOOR

Kalau semua bucket lebarnya sama, misalnya tiap 25 ribu, FLOOR jauh lebih ringkas dari CASE.

SELECT
  FLOOR(total / 25000) * 25000 AS bucket_bawah,
  COUNT(*) AS jumlah
FROM transaksi
GROUP BY FLOOR(total / 25000)
ORDER BY bucket_bawah;

FLOOR(total / 25000) ngasih nomor bucket. Transaksi 60 ribu jadi FLOOR(2,4) = 2. Dikali 25000 lagi biar labelnya jadi batas bawah bucket, yaitu 50000. Jadi transaksi itu masuk bucket "50000".

Satu rumus, jumlah bucket nggak terbatas, otomatis ngikutin data. Ganti angka 25000 buat ubah lebar bucket. Ini cara favoritku kalau bucket-nya seragam.

Fungsi WIDTH_BUCKET di PostgreSQL

PostgreSQL punya fungsi khusus histogram: WIDTH_BUCKET. Kamu kasih nilai, batas bawah, batas atas, dan jumlah bucket, dia yang bagi.

SELECT
  WIDTH_BUCKET(total, 0, 200000, 8) AS bucket,
  COUNT(*) AS jumlah
FROM transaksi
GROUP BY 1
ORDER BY 1;

Ini bikin 8 bucket rata dari 0 sampai 200 ribu, jadi tiap bucket lebarnya 25 ribu. Nilai di bawah 0 masuk bucket 0, nilai di atas 200 ribu masuk bucket 9. Jadi ada bucket luapan otomatis di dua ujung.

WIDTH_BUCKET rapi, tapi kunci ke PostgreSQL. Kalau query-mu harus jalan di banyak database, balik ke FLOOR. Detailnya ada di dokumentasi fungsi matematika PostgreSQL.

Cara nampilin bucket yang kosong

Masalah klasik histogram: bucket yang nggak punya data hilang dari hasil. Kalau nggak ada transaksi di rentang 150 sampai 175 ribu, baris itu nggak muncul, dan chart-mu bolong tanpa penjelasan.

Solusinya bikin daftar bucket lengkap dulu, lalu LEFT JOIN ke datanya. Di PostgreSQL pakai generate_series.

WITH semua_bucket AS (
  SELECT generate_series(0, 7) AS b
),
data AS (
  SELECT FLOOR(total / 25000) AS b, COUNT(*) AS jumlah
  FROM transaksi
  GROUP BY 1
)
SELECT
  semua_bucket.b * 25000 AS bucket_bawah,
  COALESCE(data.jumlah, 0) AS jumlah
FROM semua_bucket
LEFT JOIN data ON semua_bucket.b = data.b
ORDER BY semua_bucket.b;

generate_series bikin daftar bucket 0 sampai 7 walaupun datanya kosong. LEFT JOIN nyambungin ke hitungan asli. COALESCE ngubah NULL jadi 0 buat bucket yang nggak ada isinya. Hasilnya histogram tanpa lubang.

Cara bikin deret angka kayak generate_series aku bahas lebih lanjut di Generate Deret Tanggal di SQL.

Contoh kasus: sebaran nilai transaksi toko_berkah

Dataset toko_berkah punya 8.412 transaksi. Rata-rata nilai transaksi Rp 61.400. Tapi rata-rata nyembunyiin bentuk sebaran. Aku bikin histogram pakai FLOOR tiap 25 ribu.

Rentang nilaiJumlah transaksiPorsi
0-25rb2.94035%
25rb-50rb2.61231%
50rb-100rb1.87622%
100rb ke atas98412%

Rata-rata bilang 61 ribu, tapi histogram nunjukin cerita lain: 66% transaksi ada di bawah 50 ribu. Sebarannya mencong ke kiri, ditarik naik sama ekor transaksi besar yang cuma 12%.

Ini yang bikin pemiliknya mikir ulang soal minimum belanja gratis ongkir. Mereka semula pasang di 100 ribu, padahal cuma 12% transaksi yang nyampe segitu. Turunin ke 50 ribu langsung nyentuh 34% pelanggan tambahan yang belanjanya di rentang 25 sampai 50 ribu.

Median transaksinya Rp 38.500, jauh di bawah rata-rata. Selisih median dan rata-rata ini sinyal jelas sebaran yang nggak simetris. Histogram yang bikin itu kelihatan.

Kesalahan umum waktu bikin histogram di SQL

Bucket kosong hilang. Tanpa join ke daftar bucket lengkap, rentang tanpa data lenyap dari hasil. Chart jadi nyesatin. Pakai generate_series plus LEFT JOIN.

Batas bucket tumpang tindih. Nulis WHEN total <= 25000 lalu WHEN total >= 25000 bikin nilai 25000 kehitung dua kali. Konsisten pakai satu sisi, biasanya batas bawah inklusif dan batas atas eksklusif.

Lupa urutan. Tanpa ORDER BY, bucket keluar acak dan histogram jadi susah dibaca. Selalu ORDER BY batas bucket.

Lebar bucket asal. Bucket kekecilan bikin histogram penuh noise, kegedean bikin pola ketutup. Coba beberapa lebar, lihat mana yang polanya paling jelas.

NULL ikut masuk. Nilai NULL di kolom yang dibucket bisa bikin baris aneh. Tambahin WHERE total IS NOT NULL kalau perlu.

FAQ

Kapan pakai CASE WHEN dan kapan pakai FLOOR buat histogram?

Pakai FLOOR kalau semua bucket lebarnya sama, misalnya tiap 25 ribu. Satu rumus, ringkas, dan jumlah bucket ngikut data otomatis. Pakai CASE WHEN kalau bucket-nya lebar beda-beda sesuai logika bisnis, misalnya "0 sampai 50rb" lalu langsung "50rb sampai 500rb". CASE juga lebih enak kalau kamu mau label deskriptif kayak "murah", "sedang", "mahal". Buat sebaran teknis dengan bucket seragam, FLOOR menang di keringkasan.

Gimana cara nentuin lebar bucket yang bagus?

Nggak ada angka ajaib, tapi ada patokan. Mulai dari sekitar 5 sampai 15 bucket buat sebagian besar data. Kalau bucket-nya lebih dari 20, histogram jadi penuh noise dan pola kabur. Kalau kurang dari 5, detail sebaran ketutup. Cara praktisnya: hitung dulu nilai minimum dan maksimum, bagi selisihnya jadi sekitar 10 bagian, lalu bulatkan lebarnya ke angka enak kayak 25 ribu atau 50 ribu. Coba beberapa lebar dan lihat mana yang paling jelas.

Kenapa bucket kosong nggak muncul di hasil query saya?

Karena GROUP BY cuma bikin baris buat nilai yang beneran ada di data. Kalau nggak ada transaksi di rentang tertentu, GROUP BY nggak punya apa-apa buat dikelompokin di situ, jadi barisnya nggak ada. Buat maksa bucket kosong tetap muncul, bikin daftar semua bucket dulu pakai generate_series, lalu LEFT JOIN ke data aslinya dan pakai COALESCE buat ngubah NULL jadi 0. Tanpa ini, histogram-mu bisa nyesatin soalnya rentang kosong seolah nggak ada.

Apa bedanya WIDTH_BUCKET dan FLOOR?

FLOOR bikin bucket tanpa batas atas, jumlah bucket ngikut sampai nilai tertinggi di data. WIDTH_BUCKET kamu tentuin batas bawah, batas atas, dan jumlah bucket, dan dia otomatis bikin bucket luapan buat nilai di luar rentang itu. WIDTH_BUCKET lebih terkontrol kalau kamu mau rentang tetap, misalnya selalu 0 sampai 200 ribu. Tapi WIDTH_BUCKET cuma ada di PostgreSQL dan Oracle. FLOOR jalan di semua database, jadi lebih portabel.

Bisa nggak bikin histogram langsung jadi bar chart di SQL?

SQL murni cuma ngeluarin angka, bukan gambar. Tapi kamu bisa bikin bar teks kasar pakai fungsi REPEAT, misalnya REPEAT('#', jumlah / 100) buat gambar batang dari tanda pagar. Buat visual beneran, ekspor hasil query ke tools chart kayak Metabase, Looker Studio, atau tempel ke spreadsheet. Alur yang biasa: SQL ngeluarin tabel bucket dan jumlah, lalu tools visualisasi yang gambar batangnya.

Penutup

Ringkasnya:

  • CASE WHEN buat bucket dengan lebar beda-beda, jalan di semua database.
  • FLOOR buat bucket lebar sama, satu rumus dan ringkas.
  • Jangan lupa isi bucket kosong pakai generate_series plus LEFT JOIN biar histogram nggak nyesatin.

Ambil satu kolom angka di tabelmu, entah nilai transaksi, umur, atau durasi, tempel query FLOOR di atas. Dalam satu run kamu udah lihat bentuk sebarannya, bukan cuma rata-ratanya.

Mau lengkapin gambaran sebaran? Pasangkan sama median dan percentile buat angka ringkasnya, dan cek glosarium histogram di NgulikSQL buat latihan query.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel terkait

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain
Tutorial SQL
14 November 2026•8 menit baca

Semi Join dan Anti Join di SQL: Filter Pakai Tabel Lain

Semi join ngambil baris yang punya pasangan di tabel lain, anti join ngambil yang nggak punya. Keduanya filter, bukan gabung kolom. Ini cara nulisnya di SQL pakai EXISTS dan NOT EXISTS.

BimaBima
EXISTS vs IN di SQL: Perbedaan dan Performa (2026)
Tutorial SQL
11 November 2026•9 menit baca

EXISTS vs IN di SQL: Perbedaan dan Performa (2026)

EXISTS dan IN sama-sama nyaring baris pakai subquery, tapi cara kerja dan performanya beda. Ini panduan milih yang tepat plus jebakan NULL-nya.

BimaBima
Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom
Tutorial SQL
2 November 2026•11 menit baca

Crosstab (Pivot) di PostgreSQL: Ubah Baris Jadi Kolom

Crosstab di PostgreSQL mivot data dari format panjang (baris) jadi format lebar (kolom), mirip pivot table Excel. Butuh extension tablefunc, dan ada alternatif pakai CASE atau FILTER kalau kolomnya tetap.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore