Menghitung Pertumbuhan Day over Day di SQL (2026)
TL;DR
Pertumbuhan day over day (DoD) di SQL dihitung dengan membandingkan nilai hari ini dan hari sebelumnya, biasanya pakai window function LAG(). Rumusnya: nilai hari ini dikurang nilai kemarin, dibagi nilai kemarin, dikali 100. LAG() ngambil nilai dari baris sebelumnya tanpa perlu self join, jadi query jauh lebih ringkas dan cepat.
Pertumbuhan day over day di SQL dihitung dengan membandingkan nilai hari ini sama nilai kemarin, terus dijadiin persentase. Cara paling bersih pakai LAG(), window function yang ngambil nilai dari baris sebelumnya tanpa perlu join rumit.
Kalau kamu masih ngitung pertumbuhan harian pakai self join atau ekspor ke Excel dulu, artikel ini bakal motong kerjaan itu jadi satu query. LAG() bikin logikanya jauh lebih pendek.
Kita bahas rumusnya, query lengkap, cara nangani pembagian nol dan tanggal bolong, plus contoh nyata dari penjualan harian toko_berkah.
Apa itu pertumbuhan day over day?
Day over day (DoD) adalah persentase perubahan sebuah angka dibanding hari sebelumnya. Kalau penjualan hari ini 5 juta dan kemarin 4 juta, pertumbuhannya 25% DoD. Metrik ini dipakai buat mantau tren harian, deteksi lonjakan mendadak, dan ngukur dampak promo yang jalan hari itu.
DoD lebih sensitif dari perbandingan bulanan. Gerakan kecil harian langsung kelihatan, jadi cocok buat bisnis yang ritmenya cepat kayak ritel atau ecommerce.
Rumus dasarnya gampang:
DoD (%) = (nilai_hari_ini - nilai_kemarin) / nilai_kemarin * 100Tantangannya bukan di rumus, tapi gimana ngambil "nilai_kemarin" di SQL secara rapi. Di situ LAG() masuk.
Apa itu LAG() dan kenapa dipakai?
LAG() adalah window function yang ngambil nilai dari baris sebelumnya dalam urutan yang kamu tentuin. Jadi buat tiap baris hari ini, LAG() bisa ngasih nilai hari kemarin di kolom yang sama. Ini yang bikin perhitungan DoD gak butuh self join yang panjang.
LAG() termasuk window function, jenis fungsi yang ngitung sesuatu berdasarkan sekumpulan baris tanpa nge-grup datanya jadi satu. Beda sama GROUP BY yang ngeringkas baris, window function nyimpen semua baris tapi nambahin kolom hasil hitungan.
Bentuk dasarnya:
LAG(kolom) OVER (ORDER BY tanggal)Bagian OVER (ORDER BY tanggal) itu penting. Dia yang nentuin urutan baris, jadi LAG() tau mana yang "sebelumnya". Tanpa ORDER BY yang bener, hasilnya ngaco. Dokumentasi resmi soal ini ada di tutorial window function PostgreSQL.
Gimana query lengkap menghitung DoD di SQL?
Query DoD lengkap ngambil nilai hari ini, ambil nilai kemarin pakai LAG(), lalu hitung selisih dan persentasenya dalam satu SELECT. Bungkus pembagian dengan NULLIF biar aman dari pembagian nol. Urutan pakai ORDER BY tanggal supaya LAG() ngambil baris yang bener.
Anggap ada tabel penjualan_harian dengan kolom tanggal dan total_penjualan. Ini query-nya:
SELECT
tanggal,
total_penjualan,
LAG(total_penjualan) OVER (ORDER BY tanggal) AS penjualan_kemarin,
total_penjualan - LAG(total_penjualan) OVER (ORDER BY tanggal) AS selisih,
ROUND(
(total_penjualan - LAG(total_penjualan) OVER (ORDER BY tanggal)) * 100.0
/ NULLIF(LAG(total_penjualan) OVER (ORDER BY tanggal), 0),
2) AS pertumbuhan_dod_persen
FROM penjualan_harian
ORDER BY tanggal;Beberapa hal yang perlu diperhatiin:
- * 100.0 pakai desimal biar hasil pembagiannya gak dibulatin jadi integer.
- NULLIF(..., 0) mencegah error kalau penjualan kemarin nol.
- ROUND(..., 2) ngerapiin jadi dua angka di belakang koma.
- Baris pertama bakal punya pertumbuhan NULL, karena gak ada hari sebelumnya. Itu wajar.
Kalau tabelmu masih berupa transaksi mentah, kamu perlu agregasi harian dulu pakai GROUP BY. Aku bahas polanya di GROUP BY dan HAVING.
Gimana kalau LAG() diulang bikin query berantakan?
Pakai CTE atau subquery biar LAG() cuma ditulis sekali. Nulis LAG() tiga kali di satu SELECT bikin query panjang dan susah dibaca. Dengan menaruh hasil LAG() di satu langkah dulu, perhitungan selanjutnya tinggal ngacu ke kolom itu.
Versi yang lebih bersih pakai common table expression:
WITH harian AS (
SELECT
tanggal,
total_penjualan,
LAG(total_penjualan) OVER (ORDER BY tanggal) AS penjualan_kemarin
FROM penjualan_harian
)
SELECT
tanggal,
total_penjualan,
penjualan_kemarin,
total_penjualan - penjualan_kemarin AS selisih,
ROUND((total_penjualan - penjualan_kemarin) * 100.0
/ NULLIF(penjualan_kemarin, 0), 2) AS pertumbuhan_dod_persen
FROM harian
ORDER BY tanggal;Sama hasilnya, tapi jauh lebih enak dibaca. LAG() cuma nongol sekali di dalam CTE, sisanya tinggal pakai nama kolom penjualan_kemarin.
Contoh kasus: pertumbuhan harian toko_berkah
Toko_berkah mau lihat pertumbuhan penjualan harian selama seminggu promo akhir tahun. Datanya per hari, dari tanggal 8 sampai 14 Desember.
| Tanggal | Penjualan | Kemarin | DoD % |
|---|---|---|---|
| 08 Des | 4.200.000 | NULL | NULL |
| 09 Des | 4.850.000 | 4.200.000 | +15,48 |
| 10 Des | 4.600.000 | 4.850.000 | -5,15 |
| 11 Des | 6.900.000 | 4.600.000 | +50,00 |
| 12 Des | 7.100.000 | 6.900.000 | +2,90 |
| 13 Des | 5.300.000 | 7.100.000 | -25,35 |
| 14 Des | 5.450.000 | 5.300.000 | +2,83 |
Yang menarik: lonjakan +50% di tanggal 11 pas persis sama hari owner nyebar promo di grup WhatsApp pelanggan. Tapi anjlok -25,35% di tanggal 13 juga kelihatan jelas, dan setelah dicek itu hari stok kaos best seller kosong.
Tanpa DoD, angka penjualan harian cuma keliatan naik turun biasa. Dengan persentasenya, dua kejadian penting ini langsung nongol dan bisa ditindaklanjuti.
Kesalahan umum menghitung DoD di SQL
Ini jebakan yang paling sering aku temuin:
- Lupa ORDER BY di OVER. Tanpa ini, LAG() gak tau baris mana yang sebelumnya. Hasilnya acak.
- Pembagian integer. Kalau lupa * 100.0, SQL bisa buang desimal dan hasilnya 0. Pakai angka desimal.
- Gak jaga pembagian nol. Hari yang kemarinnya nol bikin query error. Bungkus dengan NULLIF.
- Salah kira LAG() ngikut tanggal kalender. LAG() ngikut urutan baris, bukan tanggal. Kalau ada hari bolong, hasilnya bisa keliru.
Soal tanggal bolong itu penting. Kalau data tanggal 10 hilang, LAG() di tanggal 11 bakal ambil tanggal 9, dan kamu mikirnya itu H-1 padahal H-2. Buat isi tanggal kosong, cek teknik di interval tanggal SQL.
DoD, WoW, atau MoM, kapan pakai yang mana?
Pakai DoD buat bisnis yang gerakannya cepat dan promonya harian. Buat pola yang kena efek hari dalam seminggu (misal ramai di weekend), week over week (WoW) lebih adil karena bandingin hari yang sama. Month over month (MoM) buat lihat tren jangka panjang tanpa noise harian.
Triknya, LAG() bisa dipakai buat ketiganya. Buat WoW, ganti jadi LAG(kolom, 7) biar ngambil 7 baris ke belakang. Buat running total dan tren kumulatif, aku bahas terpisah di running total SQL.
Penutup
Menghitung pertumbuhan day over day di SQL itu gampang begitu kamu kenal LAG(). Satu window function ngambil nilai kemarin, sisanya tinggal aritmatika persentase biasa.
Ingat tiga hal: selalu pakai ORDER BY di dalam OVER, jaga pembagian nol dengan NULLIF, dan sadar LAG() ngikut urutan baris bukan tanggal kalender.
Mau mahir window function sampai ke ROW_NUMBER dan RANK? Latihan langsung di NgulikSQL dengan dataset nyata, tanpa perlu install database. Lanjut juga ke running total SQL buat pelengkap analisa tren harianmu.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Fungsi NTH_VALUE di SQL untuk Ambil Nilai ke-N (2026)
NTH_VALUE ngambil nilai baris ke-N dalam window, tapi frame default-nya sering bikin hasil NULL. Ini sintaksnya, cara benerin frame, plus contoh transaksi toko.
Running Max dan Min dengan Window Function SQL
Lacak nilai tertinggi dan terendah berjalan di SQL pakai window function MAX dan MIN OVER. Ini sintaks, frame clause, dan contoh rekor omzet toko.
Analisa Afinitas Produk (Cross-Sell) dengan SQL
Produk apa yang sering dibeli bareng? Analisa afinitas produk pakai SQL self JOIN jawab itu. Ini cara hitung support, confidence, dan lift buat strategi cross-sell.