Mengisi Tanggal yang Kosong di Time Series SQL (2026)
TL;DR
Buat mengisi tanggal kosong di time series SQL, bikin deret tanggal lengkap pakai generate_series, lalu gabungin ke data asli pakai LEFT JOIN supaya tanggal tanpa transaksi tetap muncul. Ganti nilai NULL yang muncul jadi 0 pakai COALESCE. Teknik ini bikin grafik dan rata-rata harian jadi akurat.
Buat mengisi tanggal yang kosong di time series SQL, kamu bikin deret tanggal lengkap pakai generate_series, lalu gabungin ke data asli pakai LEFT JOIN. Tanggal yang gak punya transaksi bakal muncul dengan nilai NULL, yang tinggal kamu ganti jadi 0 pakai COALESCE.
Masalahnya sering kejadian: kamu bikin grafik penjualan harian, tapi hari yang gak ada transaksi hilang dari sumbu X. Grafiknya jadi bohong, kelihatan mulus padahal ada hari kosong.
Di sini aku tunjukin cara nutup celah ini step by step. Contohnya pakai penjualan harian toko.
Kenapa tanggal kosong jadi masalah?
Kalau kamu GROUP BY tanggal, SQL cuma ngeluarin baris buat tanggal yang punya data. Hari tanpa transaksi gak muncul sama sekali. Akibatnya rata-rata bergerak jadi salah, grafik terlihat naik terus, dan perbandingan antar periode meleset karena jumlah harinya beda.
Contoh nyata: kalau toko libur 3 hari dalam sebulan, laporan harian kamu cuma punya 27 baris, bukan 30. Analisis apa pun yang ngitung per hari bakal ketipu.
Gimana cara bikin deret tanggal lengkap?
Di PostgreSQL, pakai generate_series buat bikin satu baris per tanggal dari awal sampai akhir. Fungsi ini terima tanggal mulai, tanggal selesai, dan interval langkahnya.
SELECT generate_series(
'2026-08-01'::date,
'2026-08-31'::date,
'1 day'::interval
)::date AS tanggal;
Hasilnya 31 baris, satu buat tiap hari di bulan Agustus, tanpa ada yang bolong. Deret ini yang bakal jadi tulang laporan kamu.
Di MySQL yang gak punya generate_series, kamu bisa bikin tabel kalender permanen atau pakai recursive CTE. Tapi konsepnya sama: siapin daftar tanggal lengkap dulu.
Gimana cara menggabungkan deret tanggal ke data penjualan?
Taruh deret tanggal di sebelah kiri, lalu LEFT JOIN ke data penjualan. LEFT JOIN nahan semua tanggal dari deret, bahkan yang gak punya pasangan di tabel penjualan. Tanggal kosong bakal isi NULL di kolom penjualan.
WITH kalender AS (
SELECT generate_series(
'2026-08-01'::date,
'2026-08-31'::date,
'1 day'::interval
)::date AS tanggal
)
SELECT
k.tanggal,
COALESCE(SUM(p.omzet), 0) AS omzet_harian
FROM kalender k
LEFT JOIN penjualan p
ON p.tanggal = k.tanggal
GROUP BY k.tanggal
ORDER BY k.tanggal;
COALESCE(SUM(p.omzet), 0) ngubah NULL jadi 0. Jadi hari tanpa transaksi tetap muncul dengan omzet 0, bukan hilang. Ini kunci biar grafik dan rata-rata harian jadi jujur.
| Bagian | Tugasnya |
|---|---|
| generate_series | Bikin daftar tanggal lengkap |
| LEFT JOIN | Nahan semua tanggal, isi NULL kalau kosong |
| COALESCE | Ganti NULL jadi 0 |
Contoh kasus: penjualan harian toko_berkah
toko_berkah tutup tiap hari Minggu. Selama Agustus 2026 ada 5 hari Minggu, jadi tabel penjualan cuma punya 26 baris tanggal. Waktu dibikin grafik, sumbu X-nya loncat-loncat dan rata-rata harian kelihatan lebih tinggi dari aslinya.
Setelah pakai teknik generate_series plus LEFT JOIN, deretnya jadi 31 baris penuh dengan 5 hari bernilai 0.
Dari dataset ngulikdata, rata-rata omzet harian sebelum tanggal kosong diisi ketulis Rp 3,1 juta. Setelah 5 hari libur dimasukin dengan nilai 0, rata-rata sebenarnya turun jadi Rp 2,6 juta. Selisih Rp 500 ribu per hari itu gara-gara hari kosong yang tadinya kehilangan dari hitungan. Angka yang lebih rendah ini yang benar buat proyeksi.
Kesalahan umum saat mengisi tanggal kosong
- Pakai INNER JOIN, bukan LEFT JOIN. INNER JOIN buang tanggal yang gak punya data, jadi celahnya balik lagi. Deret tanggal wajib di sisi kiri dengan LEFT JOIN.
- Lupa COALESCE. Tanpa itu, hari kosong tetap NULL. NULL bikin SUM dan AVG di langkah berikutnya jadi meleset.
- Rentang tanggal gak nutup semua data. Kalau tanggal mulai atau selesai salah, ada data yang kepotong. Cek dulu min dan max tanggal aslinya.
- Salah tipe data. Bandingin date dengan timestamp bisa bikin JOIN gagal cocok. Samain dulu tipenya, misalnya cast timestamp ke date.
Kalau datamu per jam atau per minggu, tinggal ganti interval di generate_series, misalnya '1 hour' atau '1 week'. Logikanya tetap sama.
FAQ
Apa fungsi generate_series di SQL?
generate_series bikin sekumpulan baris berurutan, misalnya deret angka atau deret tanggal, dari nilai awal sampai akhir dengan langkah tertentu. Buat time series, fungsi ini dipakai bikin daftar tanggal lengkap tanpa ada yang bolong. Deret itu lalu digabungin ke data asli supaya tanggal kosong tetap muncul di hasil query.
Kenapa harus LEFT JOIN, bukan INNER JOIN?
LEFT JOIN nahan semua baris dari tabel kiri, yaitu deret tanggal lengkap, walau gak ada pasangan di tabel penjualan. INNER JOIN cuma keluarin baris yang cocok di dua tabel, jadi tanggal kosong bakal hilang lagi. Buat mengisi celah tanggal, deret tanggal harus di kiri dan pakai LEFT JOIN supaya hari tanpa transaksi tetap ikut.
Gimana kalau database saya MySQL yang gak punya generate_series?
MySQL versi lama gak punya generate_series. Solusinya bikin tabel kalender permanen berisi semua tanggal, lalu JOIN ke situ. Alternatif lain pakai recursive CTE di MySQL 8 buat menghasilkan deret tanggal. Setelah deret tanggalnya ada, langkah LEFT JOIN dan COALESCE-nya sama persis kayak di PostgreSQL.
Gimana mengganti NULL jadi 0 setelah join?
Pakai COALESCE, yang ngembaliin nilai pertama yang bukan NULL. Tulis COALESCE(SUM(omzet), 0), jadi kalau hasil SUM-nya NULL karena gak ada transaksi, otomatis diganti 0. Ini penting supaya perhitungan rata-rata dan total di langkah berikutnya gak keganggu nilai kosong.
Bisa gak teknik ini buat data per jam atau per minggu?
Bisa. Tinggal ganti interval di generate_series sesuai kebutuhan, misalnya '1 hour' buat data per jam atau '1 week' buat mingguan. Pastikan kolom tanggal di data asli dipangkas ke satuan yang sama, misalnya pakai DATE_TRUNC. Sisanya, LEFT JOIN dan COALESCE, tetap jalan tanpa perubahan.
Penutup
Rekap: bikin deret tanggal lengkap pakai generate_series, gabungin ke data pakai LEFT JOIN, lalu ganti NULL jadi 0 pakai COALESCE. Tiga langkah ini bikin laporan harian kamu jujur.
Coba jalanin query ini di data penjualan kamu, lalu bandingin rata-rata hariannya sebelum dan sesudah. Bedanya sering bikin kaget.
Mau lanjut ngulik SQL tanggal? Baca cara generate deret tanggal di SQL dan cara ringkas tanggal pakai DATE_TRUNC. Buat konsep dasarnya, cek glosarium time series dan halaman fungsi COALESCE. Dokumentasi resmi ada di dokumentasi PostgreSQL untuk generate_series.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Composite Index di SQL: Cara Kerja dan Urutan Kolom
Composite index itu index atas beberapa kolom sekaligus. Urutan kolomnya nentuin query mana yang kebantu, lewat aturan leftmost prefix.
Menghitung Stickiness (DAU/MAU) di SQL
Stickiness ngukur seberapa sering user balik lagi. Ini cara hitung DAU, MAU, dan rasio stickiness pakai SQL, plus contoh aplikasi UMKM.
Menghitung DAU dan MAU dengan SQL
DAU dan MAU dua metrik wajib buat produk digital. Ini cara hitungnya pakai SQL, lengkap query DISTINCT, per bulan, sampai rasio stickiness.