SQL Date Bucketing: Kelompokkan Data per Rentang Waktu
TL;DR
Date bucketing di SQL adalah teknik ngelompokkin tanggal ke dalam rentang tertentu, misalnya per bulan atau berdasarkan umur transaksi (0-7 hari, 8-30 hari). Ada dua cara utama: DATE_TRUNC buat rentang kalender yang rapi, dan CASE WHEN buat bucket kustom sesuai selisih hari.
Date bucketing di SQL adalah teknik ngelompokkin tanggal ke dalam rentang tertentu, misalnya per bulan atau berdasarkan umur transaksi kayak 0-7 hari dan 8-30 hari. Tujuannya biar data mentah yang penuh tanggal acak bisa dibaca sebagai kelompok yang rapi.
Kalau kamu pernah bikin laporan penjualan per minggu atau ngukur berapa banyak pelanggan yang belum belanja lebih dari sebulan, kamu udah butuh bucketing. Di bawah ini ada dua cara utama, contoh query siap pakai, dan data order toko yang bisa langsung kamu coba.
Apa itu date bucketing di SQL?
Date bucketing adalah proses ngubah kolom tanggal jadi label rentang yang bisa di-GROUP BY. Daripada ngitung tiap tanggal satu-satu, kamu kelompokkan dulu jadi ember (bucket) kayak per bulan, per kuartal, atau per selisih hari. Hasilnya jauh lebih gampang dibaca dan dibikin grafik.
Ada dua gaya bucketing yang paling sering dipakai analis. Pertama, rentang kalender yang teratur pakai DATE_TRUNC. Kedua, rentang kustom pakai CASE WHEN.
Gimana cara bucketing per bulan pakai DATE_TRUNC?
DATE_TRUNC motong tanggal ke awal periode. Jadi 2026-05-18 yang di-truncate ke bulan bakal jadi 2026-05-01. Semua tanggal di bulan yang sama jatuh ke nilai yang sama, tinggal di-GROUP BY.
SELECT
DATE_TRUNC('month', order_date) AS bulan,
COUNT(*) AS jumlah_order,
SUM(total_amount) AS total_omzet
FROM orders
GROUP BY DATE_TRUNC('month', order_date)
ORDER BY bulan;
Ganti 'month' jadi 'week', 'quarter', atau 'year' sesuai kebutuhan. Cara ini cocok buat grafik tren yang butuh rentang berturut-turut. Mau tau lebih dalam soal fungsi ini? Baca panduan DATE_TRUNC.
Gimana cara bikin bucket kustom pakai CASE WHEN?
Kalau batas rentangmu nggak seragam, DATE_TRUNC nggak cukup. Contohnya kamu mau kelompokkin order berdasarkan umurnya: yang baru (0-7 hari), yang sedang (8-30 hari), dan yang lama (30+ hari). Di sini CASE WHEN yang kerja.
SELECT
CASE
WHEN DATE '2026-07-16' - order_date <= 7 THEN '0-7 hari'
WHEN DATE '2026-07-16' - order_date <= 30 THEN '8-30 hari'
ELSE '30+ hari'
END AS umur_bucket,
COUNT(*) AS jumlah_order
FROM orders
GROUP BY 1;
Di PostgreSQL, selisih dua kolom DATE langsung ngasih jumlah hari dalam bentuk angka. Di database lain kamu mungkin perlu DATEDIFF atau fungsi serupa. Prinsipnya sama: hitung selisih hari, lalu petakan ke label.
Contoh kasus: recency order toko_berkah
Pakai data order toko_berkah di bawah. Anggap hari ini 16 Juli 2026, dan kamu mau lihat sebaran umur order buat nentuin mana pelanggan yang perlu di-follow up.
order_id | order_date | total_amount
1 | 2026-05-02 | 150000
2 | 2026-05-18 | 275000
3 | 2026-06-05 | 90000
4 | 2026-06-22 | 320000
5 | 2026-07-01 | 60000
6 | 2026-07-10 | 480000
Setelah query CASE WHEN dijalanin, hasilnya: bucket 0-7 hari isi 1 order, bucket 8-30 hari isi 2 order, dan bucket 30+ hari isi 3 order. Dari sini kelihatan setengah dari order (3 dari 6) umurnya udah lewat sebulan. Buat toko yang jual barang cepat habis, itu sinyal buat ngingetin pelanggan lama biar balik belanja.
Angka bucket kayak gini bisa langsung kamu pakai buat segmentasi. Mau lanjut cari deretan tanggal yang bolong di data transaksi? Cek teknik di Gap and Island Analysis.
Bucketing per minggu dan per jam
Buat laporan mingguan, ganti unit DATE_TRUNC:
SELECT DATE_TRUNC('week', order_date) AS minggu, COUNT(*)
FROM orders
GROUP BY 1
ORDER BY minggu;
Kalau kolommu punya jam (timestamp), kamu juga bisa bucket per jam pakai DATE_TRUNC('hour', order_time), atau bikin bucket pagi-siang-sore pakai EXTRACT(HOUR FROM order_time) di dalam CASE WHEN.
Kesalahan umum saat date bucketing
- Batas bucket tumpang tindih - kalau satu bucket <= 7 dan bucket lain >= 7, tanggal di angka 7 bisa kehitung dobel. Bikin batasnya nyambung tanpa overlap.
- Bucket kosong ilang - GROUP BY cuma nampilin bucket yang ada datanya. Kalau kamu butuh semua rentang muncul, LEFT JOIN ke tabel referensi bucket.
- Salah hari awal minggu - DATE_TRUNC di PostgreSQL mulai minggu dari Senin. Cek dokumentasi database kamu, karena beda engine bisa beda.
- Lupa timezone - kalau kolomnya timestamp with time zone, hasil truncate bisa geser sehari. Samain timezone dulu sebelum bucketing.
DATE_TRUNC atau CASE WHEN?
| Kebutuhan | Pakai |
|---|---|
| Rentang kalender teratur (bulan, minggu) | DATE_TRUNC |
| Rentang umur kustom (0-7, 8-30 hari) | CASE WHEN |
| Grafik tren berturut-turut | DATE_TRUNC |
| Segmentasi recency pelanggan | CASE WHEN |
Sering kali kamu pakai keduanya di laporan yang sama. DATE_TRUNC buat sumbu waktu, CASE WHEN buat ngelabelin segmen.
FAQ
Pertanyaan yang sering muncul soal date bucketing ada di bagian bawah ini.
Apa bedanya date bucketing pakai DATE_TRUNC sama CASE WHEN?
DATE_TRUNC motong tanggal ke awal periode kalender, misalnya awal bulan atau awal minggu, jadi cocok buat rentang yang teratur dan berturut-turut. CASE WHEN dipakai kalau kamu mau bucket kustom yang batasnya nggak sama, misalnya 0-7 hari, 8-30 hari, lalu 30 hari ke atas. Pilih DATE_TRUNC buat tren waktu, CASE WHEN buat segmentasi umur.
Gimana cara bucketing tanggal per minggu di SQL?
Pakai DATE_TRUNC('week', kolom_tanggal) di PostgreSQL, hasilnya bakal ngasih tanggal awal tiap minggu (Senin). Lalu GROUP BY hasil itu buat ngitung total per minggu. Di database lain sintaksnya beda: MySQL pakai YEARWEEK, BigQuery pakai DATE_TRUNC(tanggal, WEEK). Cek dokumentasi database kamu buat memastikan hari awal minggunya.
Kenapa hasil bucket aku ada yang kelewat atau kosong?
Biasanya karena rentang di CASE WHEN kamu tumpang tindih atau ada celah. Pastikan batas tiap bucket nyambung tanpa lubang, misalnya <= 7 lalu bucket berikutnya mulai dari 8. Bucket yang kosong juga wajar kalau memang nggak ada data di rentang itu. Kalau kamu butuh semua rentang tetap muncul, gabungin sama tabel referensi bucket pakai LEFT JOIN.
Bisa nggak bucketing berdasarkan jam, bukan tanggal?
Bisa. DATE_TRUNC('hour', kolom_waktu) bakal ngelompokkin data per jam. Buat bucket kustom kayak pagi, siang, sore, malam, pakai EXTRACT(HOUR FROM kolom_waktu) di dalam CASE WHEN. Ini kepake buat lihat pola jam ramai transaksi. Misal jam 19-21 sering jadi puncak order di toko online.
Penutup
Date bucketing bikin tanggal mentah jadi kelompok yang bisa dibaca. Inget dua alat utamanya: DATE_TRUNC buat rentang kalender, CASE WHEN buat rentang kustom. Pastiin batas bucket nyambung biar nggak ada data yang dobel atau kelewat.
Mau latihan query bucketing langsung di browser tanpa install database? Coba latihan interaktif di NgulikSQL. Buat referensi teknis, cek dokumentasi resmi PostgreSQL Date/Time Functions.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
CTE vs Subquery vs Temp Table: Mana Lebih Cepat
CTE, subquery, dan temp table sama-sama bikin hasil sementara, tapi performanya beda. Ini panduan milih yang mana buat query kamu.
Partisi Tabel di SQL untuk Data Besar
Partisi tabel memecah satu tabel besar jadi potongan kecil biar query cuma baca bagian yang relevan. Ini cara bikin dan kapan kamu butuh.
Covering Index di SQL untuk Query Lebih Cepat (2026)
Covering index bikin query cepat karena semua kolom yang dibutuhin ada di index, jadi database nggak perlu buka tabel utama.