Menghitung Rolling 7 Hari di SQL (2026)
TL;DR
Rolling 7 hari (moving average 7 hari) di SQL dihitung pakai window function AVG() OVER dengan frame ROWS BETWEEN 6 PRECEDING AND CURRENT ROW. Frame ini ngambil baris hari ini plus 6 hari sebelumnya, lalu diratain. Hasilnya angka yang lebih mulus buat lihat tren tanpa keganggu fluktuasi harian atau efek akhir pekan. Data harus urut per tanggal dan gak boleh ada tanggal bolong.
Rolling 7 hari di SQL dihitung pakai window function dengan frame ROWS BETWEEN 6 PRECEDING AND CURRENT ROW. Frame ini ngambil baris hari ini plus 6 hari sebelumnya, lalu diratain jadi satu angka.
Gunanya buat ngeratain data harian yang naik-turun. Penjualan hari Sabtu selalu beda sama Selasa, dan fluktuasi itu bikin tren susah kebaca. Rolling 7 hari ngilangin efek hari dalam seminggu.
Aku bahas cara bikinnya dari nol, plus dua variasi frame yang sering ketuker. Query di sini pakai PostgreSQL, tapi logikanya sama di MySQL 8, SQL Server, dan BigQuery.
Apa itu rolling 7 hari di SQL?
Rolling 7 hari adalah rata-rata bergerak yang ngitung nilai hari ini bareng 6 hari sebelumnya. Tiap baris punya rata-ratanya sendiri dari jendela 7 hari yang geser terus. Hasilnya garis yang lebih mulus dari data mentah, jadi tren naik atau turun lebih gampang keliatan.
Alatnya window function, khususnya bagian frame yang nentuin baris mana aja yang masuk perhitungan. Konsep dasar window function aku bahas di glosarium window function. Rolling average salah satu penerapannya yang paling sering dipakai analis.
Gimana cara nulis query rolling 7 hari?
Pakai AVG(nilai) OVER (ORDER BY tanggal ROWS BETWEEN 6 PRECEDING AND CURRENT ROW). Bagian ORDER BY tanggal ngurutin barisnya, dan frame ROWS BETWEEN 6 PRECEDING AND CURRENT ROW nentuin jendela 7 barisnya. Data harus satu baris per tanggal biar hasilnya bener.
SELECT
tanggal,
omzet,
AVG(omzet) OVER (
ORDER BY tanggal
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS rolling_7hari
FROM penjualan_harian
ORDER BY tanggal;
Angka 6 di situ artinya 6 baris ke belakang, ditambah baris sekarang, jadi total 7. Kalau mau rolling 30 hari, ganti jadi 29. Hasil rolling ngikut tiap baris, geser satu hari tiap turun ke bawah.
Kenapa pakai ROWS, bukan RANGE?
ROWS ngitung berdasarkan jumlah baris, RANGE berdasarkan nilai. Buat rolling 7 hari, ROWS lebih aman kalau datamu udah satu baris per tanggal. RANGE bisa beda hasil kalau ada tanggal kembar atau kamu pengen jendela berbasis rentang tanggal beneran, bukan hitungan baris.
| Frame | Ngitung | Aman kalau |
|---|---|---|
ROWS 6 PRECEDING | 6 baris terakhir | Satu baris per tanggal, gak bolong |
RANGE '6 days' | Rentang tanggal 6 hari | Ada tanggal bolong atau kembar |
Kalau ada tanggal yang gak ada transaksinya, ROWS bakal ngambil 7 baris yang ada, bukan 7 hari kalender. Ini bisa bikin hasil meleset. Buat data yang mungkin bolong, siapin dulu deret tanggal lengkap.
Contoh kasus: penjualan harian toko_berkah
Toko_berkah punya penjualan harian yang naik-turun tajam. Weekend rame, Senin sepi. Owner bingung apakah bisnisnya lagi naik atau cuma efek hari biasa. Aku tarik 14 hari dan hitung rolling 7 harinya.
| Tanggal | Omzet Harian | Rolling 7 Hari |
|---|---|---|
| 7 Jul (Sen) | Rp 3,2 jt | n/a |
| 12 Jul (Sab) | Rp 8,1 jt | Rp 5,4 jt |
| 13 Jul (Min) | Rp 7,6 jt | Rp 5,6 jt |
| 14 Jul (Sen) | Rp 3,5 jt | Rp 5,7 jt |
Omzet harian loncat dari 3,2 juta ke 8,1 juta, keliatan liar. Tapi rolling 7 harinya naik pelan dari 5,4 ke 5,7 juta. Itu bukti tren beneran naik, bukan cuma efek weekend.
Yang menarik, waktu aku bandingin rata-rata rolling minggu ini sama minggu lalu, ada kenaikan 6,1%. Angka ini konsisten dan gak keganggu satu hari libur nasional yang bikin omzet harian sempet drop 40%. Owner akhirnya pakai garis rolling ini buat mutusin nambah stok, bukan angka harian yang bikin panik.
Buat bandingin pertumbuhan antar minggu secara lebih formal, aku bahas caranya di artikel week over week SQL.
Kesalahan umum waktu hitung rolling
Lupa ORDER BY di dalam OVER. Tanpa urutan tanggal, window gak tahu mana "6 baris sebelumnya". Hasilnya acak. ORDER BY di dalam OVER itu beda sama ORDER BY di akhir query dan dua-duanya perlu.
Tanggal bolong bikin jendela meleset. ROWS ngitung baris, bukan hari. Kalau ada tanggal tanpa data, 7 baris terakhir bisa mencakup lebih dari 7 hari kalender. Isi dulu tanggal kosong biar akurat.
Pakai 7 PRECEDING padahal maunya 7 hari. 6 PRECEDING plus baris sekarang udah 7 baris. Kalau kamu tulis 7 PRECEDING, jendelanya jadi 8 hari. Kurangi satu dari jumlah hari yang kamu mau.
Belum agregasi ke harian. Kalau tabelmu masih per transaksi, satu tanggal punya banyak baris. Ratain dulu ke satu baris per hari pakai GROUP BY sebelum bikin rolling.
FAQ
Apa beda rolling average dan simple average?
Simple average ngitung satu rata-rata buat seluruh data. Rolling average ngitung rata-rata yang beda buat tiap baris, dari jendela yang geser terus. Rolling bikin kamu lihat gimana rata-rata berubah dari waktu ke waktu, bukan cuma satu angka final. Ini penting buat ngelacak tren, karena satu rata-rata global nyembunyiin naik-turun yang terjadi di sepanjang periode.
Gimana cara hitung rolling 30 hari?
Ganti angka di frame jadi 29 PRECEDING. Jadi ROWS BETWEEN 29 PRECEDING AND CURRENT ROW, karena 29 baris ke belakang plus baris sekarang totalnya 30. Logikanya sama persis dengan rolling 7 hari, cuma beda ukuran jendela. Buat rolling N hari, selalu pakai (N-1) PRECEDING. Pastiin datamu satu baris per tanggal biar hitungan barisnya sama dengan hitungan hari.
Kenapa baris pertama rolling-nya beda?
Karena baris awal belum punya 6 hari sebelumnya yang lengkap. Baris pertama cuma ngeratain dirinya sendiri, baris kedua ngeratain dua hari, dan seterusnya sampai jendela penuh di baris ketujuh. Ini normal dan disebut periode pemanasan. Kalau kamu mau rolling yang cuma nampil pas jendela udah penuh, tambahin filter buat buang enam baris pertama.
Bisa gak rolling dihitung per produk atau cabang?
Bisa, tambahin PARTITION BY di dalam window. Contohnya OVER (PARTITION BY cabang ORDER BY tanggal ROWS BETWEEN 6 PRECEDING AND CURRENT ROW). Dengan gitu, rolling dihitung terpisah buat tiap cabang dan gak nyampur antar cabang. Ini berguna kalau kamu punya beberapa toko dan mau lihat tren masing-masing dalam satu query yang sama.
Apakah rolling average bisa pakai SUM atau cuma AVG?
Bisa pakai fungsi agregat apa aja di window, termasuk SUM, MAX, MIN, dan COUNT. SUM() OVER dengan frame yang sama ngasih total bergerak, bukan rata-rata. Ini kepakai buat hitung total penjualan 7 hari terakhir per hari. Tinggal ganti AVG jadi fungsi yang kamu mau, frame ROWS BETWEEN-nya tetap sama.
Penutup
Ringkasan cara hitung rolling 7 hari di SQL:
- Pakai
AVG(nilai) OVER (ORDER BY tanggal ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) - Buat rolling N hari, pakai
(N-1) PRECEDING - Data harus satu baris per tanggal dan gak boleh bolong biar akurat
Dokumentasi lengkap window frame ada di dokumentasi PostgreSQL. Buat lanjut ke perbandingan antar periode, baca cara hitung YTD, QTD, dan MTD, atau pahami dulu dasar window function.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
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.
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.
INSERT ON CONFLICT di PostgreSQL
INSERT ON CONFLICT bikin PostgreSQL insert baris baru atau update yang udah ada dalam satu perintah, tanpa error gara-gara duplikat primary key.