Checklist Validasi Query Sebelum Hasilnya Dikirim ke Atasan
TL;DR
Validasi query SQL sebelum hasilnya dikirim dilakukan lewat sepuluh pemeriksaan cepat: jumlah baris masuk akal, JOIN nggak nggandain baris, tidak ada baris yang hilang karena NULL, batas tanggal sesuai, tidak ada duplikat di kunci, dan total angkanya cocok dengan sumber lain. Query yang jalan tanpa pesan error belum tentu benar, karena kesalahan logika selalu menghasilkan angka yang kelihatan wajar.
Query yang jalan tanpa pesan error belum tentu bener.
Kesalahan logika di SQL hampir nggak pernah kelihatan sebagai error. Dia muncul sebagai angka yang kelihatan wajar, lolos ke slide, dan baru ketahuan pas ada yang nanya kenapa omzetnya beda sama laporan keuangan.
Sepuluh pemeriksaan di bawah ini bisa kamu jalanin dalam 5 menit. Urutannya dari yang paling sering bikin salah.
Kenapa hasil query perlu divalidasi dulu?
Karena database cuma ngejalanin apa yang kamu tulis, bukan apa yang kamu maksud. Salah satu tanda kutip di filter status, satu JOIN yang nggandain baris, atau batas tanggal yang kelewat satu hari semuanya menghasilkan angka yang terlihat masuk akal.
Biaya salahnya nggak seimbang. Ngecek makan 5 menit, sementara narik balik angka yang udah dipakai buat keputusan makan waktu berhari-hari plus kredibilitasmu.
Sepuluh pemeriksaan validasi query
| No | Yang dicek | Cara cepat | Tanda bahaya |
|---|---|---|---|
| 1 | Jumlah baris masuk akal | COUNT sebelum dan sesudah | Naik atau turun drastis |
| 2 | JOIN nggandain baris | COUNT dibanding COUNT DISTINCT kunci | Dua angkanya beda |
| 3 | Baris hilang gara-gara INNER JOIN | LEFT JOIN lalu cek IS NULL | Ada baris tanpa pasangan |
| 4 | Batas tanggal | MIN dan MAX tanggal di hasil | Kelebihan atau kurang sehari |
| 5 | Duplikat di kolom kunci | GROUP BY dengan HAVING COUNT lebih dari 1 | Ada baris kembar |
| 6 | NULL kebuang filter | Hitung jumlah NULL per kolom | Kolom filter banyak kosongnya |
| 7 | Filter status | Lihat daftar nilai unik status | Transaksi batal ikut kehitung |
| 8 | Pembagian nol | Bungkus penyebut pakai NULLIF | Error atau hasil tak hingga |
| 9 | Nilai ekstrem | MIN, MAX, AVG per kolom angka | Nominal minus atau kelewat besar |
| 10 | Rekonsiliasi total | Banding sama satu sumber lain | Selisih di atas 1% |
Pemeriksaan mana yang paling sering nyelametin?
Fan-out JOIN. Ini kejadian waktu satu baris di tabel kiri ketemu banyak baris pasangan di tabel kanan, jadi baris aslinya berlipat dan semua penjumlahan jadi kegedean.
Gejalanya khas: total penjualan tiba-tiba naik dua kali lipat setelah kamu nambah satu JOIN yang "cuma buat ngambil nama kota".
-- Sebelum JOIN
SELECT COUNT(*) FROM transaksi;
-- Sesudah JOIN, dua angka ini harus sama
SELECT COUNT(*) AS baris_hasil,
COUNT(DISTINCT t.transaksi_id) AS transaksi_unik
FROM transaksi t
JOIN alamat a ON a.pelanggan_id = t.pelanggan_id;
Kalau baris_hasil lebih besar dari transaksi_unik, berarti ada pelanggan yang punya lebih dari satu alamat. Perbaikannya bisa lewat pembatasan alamat utama, atau agregasi dulu sebelum digabung.
Perilaku tiap jenis JOIN aku bahas terpisah di perbedaan JOIN di SQL.
Gimana cara ngecek batas tanggal nggak meleset?
Masalah paling umum ada di kolom bertipe timestamp yang difilter pakai BETWEEN. Kolom yang nyimpen jam bikin transaksi pukul 14.30 di tanggal akhir ikut kebuang, karena batas atasnya dibaca sebagai pukul 00.00.
| Cara nulis | Aman? | Catatan |
|---|---|---|
| BETWEEN '2025-08-01' AND '2025-08-31' | Berisiko | Kehilangan transaksi 31 Agustus setelah tengah malam |
| >= '2025-08-01' AND < '2025-09-01' | Aman | Pola setengah terbuka, kepakai buat semua tipe |
| DATE(tanggal) = '2025-08-01' | Berisiko | Bisa bikin index nggak kepakai |
Pola setengah terbuka itu kebiasaan yang paling gampang dipertahankan. Aturan tipe tanggal dan waktu di PostgreSQL bisa kamu cek di dokumentasi resmi PostgreSQL.
Kenapa hasilnya sedikit lebih kecil dari yang diharapkan?
Biasanya gara-gara NULL. Baris dengan nilai kosong nggak lolos perbandingan biasa, jadi dia diam-diam kebuang tanpa peringatan.
-- Baris dengan status NULL nggak ikut, walaupun kamu kira ikut
WHERE status <> 'batal'
-- Versi yang ngajak NULL ikut serta
WHERE (status <> 'batal' OR status IS NULL)
Sebelum bikin filter, lihat dulu daftar nilai unik di kolom itu. Sering kali ada nilai yang kamu nggak tahu keberadaannya, misalnya Batal dengan huruf besar dan batal huruf kecil sekaligus.
SELECT status, COUNT(*) AS jumlah
FROM transaksi
GROUP BY status
ORDER BY jumlah DESC;
Perilaku NULL di operasi agregat aku ringkas di glossary aggregate function, dan pemeriksaan kualitas datanya di glossary data quality.
Contoh kasus: rekonsiliasi omzet mega_retail
Aku pakai dataset ngulikdata mega_retail, jaringan toko dengan 12 cabang. Permintaannya sederhana: total omzet Agustus 2025 per cabang.
Query pertama ngasih Rp 8.417.900.000. Laporan kasir ngasih Rp 7.982.400.000. Selisihnya Rp 435.500.000, atau 5,5%.
| Pemeriksaan | Temuan | Dampak |
|---|---|---|
| Filter status | 1.284 transaksi berstatus batal ikut kehitung | Rp 391.200.000 |
| Batas tanggal | BETWEEN motong 31 Agustus sore | Kurang Rp 62.800.000 |
| Duplikat | 217 baris kembar dari impor ulang | Rp 107.100.000 |
Setelah tiga hal itu dibenerin, angkanya jadi Rp 7.983.800.000. Sisa selisihnya Rp 1.400.000, atau 0,02%, dan itu dari pembulatan pajak di sisi kasir.
Yang menarik, dua kesalahan itu arahnya berlawanan. Transaksi batal bikin angkanya kegedean, batas tanggal bikin kekecilan. Kalau kamu cuma ngecek total tanpa mecah per penyebab, selisih 5,5% bisa kelihatan seperti satu masalah kecil.
Kesalahan umum waktu validasi
- Cuma ngecek totalnya. Dua kesalahan yang saling menutupi bikin total kelihatan pas padahal angkanya salah dua kali.
- Percaya sama query yang kemarin bener. Data baru masuk tiap hari, dan status baru bisa muncul kapan aja.
- Lupa nyabut LIMIT. Kamu pasang LIMIT 100 buat ngintip, lalu lupa nyabut waktu ngirim hasil.
- Nggak nulis nama kolom yang jelas. Kolom bernama
sumbikin penerima nebak isinya. - Nggak nyimpen query yang dipakai. Bulan depan ada yang minta angka yang sama, dan kamu nggak inget filternya.
- Ngirim tanpa nyebut periode dan filternya. Angka tanpa keterangan cakupan gampang dipakai buat hal yang salah.
FAQ
Berapa lama idealnya validasi query sebelum dikirim?
Buat query harian yang polanya udah kamu kenal, 5 menit cukup: cek jumlah baris, cek fan-out, cek batas tanggal. Buat angka yang bakal dipakai buat keputusan besar atau dilihat di luar tim, sisihkan 20-30 menit dan tambahin rekonsiliasi ke satu sumber lain. Patokan praktisnya, makin banyak orang yang bakal lihat angkanya, makin lama waktu yang pantas kamu keluarkan buat ngecek.
Gimana cara tahu JOIN aku nggandain baris?
Bandingin jumlah baris hasil dengan jumlah nilai unik dari kolom kunci tabel utama. Kalau COUNT bintang lebih besar dari COUNT DISTINCT kunci, berarti ada baris yang berlipat. Cara lain yang lebih cepat, jalanin query tanpa JOIN dulu lalu catat jumlah barisnya, baru tambahin JOIN satu per satu sambil ngecek angkanya tiap kali. Begitu angkanya naik, kamu langsung tahu JOIN mana penyebabnya.
Angka query beda tipis sama laporan keuangan, wajar nggak?
Selisih di bawah 0,1% biasanya datang dari pembulatan atau beda waktu potret data, dan itu wajar asal kamu bisa jelasin sumbernya. Selisih di atas 1% hampir selalu berarti ada beda definisi, misalnya laporan keuangan ngeluarin retur sementara querymu ikut ngitung. Yang penting bukan angkanya sama persis, tapi kamu tahu persis kenapa beda dan bisa nyebutin penyebabnya.
Perlu nggak bikin query validasi terpisah tiap kali?
Buat laporan yang jalan rutin, iya. Simpan satu berkas berisi query pemeriksaan standar, lalu jalanin sebelum ngirim. Isinya cukup lima hal: jumlah baris, jumlah duplikat kunci, jumlah NULL per kolom penting, rentang tanggal, serta nilai terkecil dan terbesar kolom angka. Sekali disiapkan, ini cuma makan waktu dua menit tiap dipakai dan nyelametin kamu berkali-kali.
Kalau query lambat, boleh nggak validasinya dilewat?
Justru query lambat yang paling perlu divalidasi, karena kamu bakal males ngulang kalau hasilnya salah. Jalanin pemeriksaan di potongan data yang lebih kecil dulu, misalnya satu cabang atau satu minggu, biar cepat. Setelah logikanya kamu yakin bener, baru jalankan di rentang penuh. Cara memperbaiki kecepatannya sendiri aku bahas terpisah di artikel soal query lambat.
Penutup
Tiga hal yang perlu kamu bawa. Kesalahan SQL muncul sebagai angka wajar, bukan sebagai error. Fan-out JOIN dan filter status penyebab paling sering. Dan rekonsiliasi ke satu sumber lain wajib buat angka yang bakal dipakai ngambil keputusan.
Simpan sepuluh pemeriksaan itu jadi satu berkas SQL di folder kerjamu hari ini, biar besok tinggal jalanin.
Buat query pemeriksaan kualitas data yang lebih lengkap, baca cek kualitas data pakai SQL. Kalau kamu sering kejebak jebakan sintaks, cek kesalahan umum SQL pemula. Dan kalau querymu lambat, mulai dari cara nyari penyebab query SQL lambat.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Pivot dinamis di SQL ngubah baris jadi kolom tanpa kamu hardcode nama kolomnya. Ini cara bikinnya pakai CASE WHEN dan versi yang kolomnya ngikut data.
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
YTD, QTD, dan MTD ngukur total dari awal tahun, kuartal, atau bulan sampai hari ini. Ini cara ngitungnya di SQL pakai DATE_TRUNC, plus satu query gabungan.
Gap and Island Analysis di SQL
Gap and island analysis di SQL nyari deret data yang berturut-turut (island) dan celah yang bolong (gap). Cocok buat hitung streak login atau cari tanggal transaksi yang hilang.