Code Review SQL: Apa yang Sebenarnya Diperiksa Reviewer
TL;DR
Code review SQL adalah pemeriksaan query oleh orang lain sebelum query itu dipakai buat laporan atau masuk ke pipeline. Lima hal yang dicek berurutan: kebenaran hasil, duplikasi baris dari JOIN, penanganan NULL, performa, dan kebacaan. Urutannya penting karena query yang rapi tapi angkanya salah jauh lebih berbahaya daripada query berantakan yang benar.
Code review SQL adalah pemeriksaan query oleh orang lain sebelum query itu dipakai buat laporan atau masuk ke pipeline.
Yang dicek bukan cuma rapi atau nggaknya. Urutan pemeriksaannya begini: kebenaran hasil dulu, baru duplikasi baris, penanganan NULL, performa, dan terakhir kebacaan.
Urutan itu penting. Query rapi yang angkanya salah jauh lebih berbahaya daripada query berantakan yang benar, soalnya yang rapi lebih dipercaya orang.
Apa yang pertama dicek reviewer SQL?
Kebenaran hasil. Reviewer ngecek apakah query-nya beneran jawab pertanyaan yang diminta, bukan pertanyaan mirip. Cara paling cepat: bandingin satu angka hasil query sama angka dari sumber lain yang udah dipercaya, misalnya laporan bulanan atau dasbor yang udah jalan.
Empat pertanyaan yang aku ajukan ke diri sendiri sebelum baca detail sintaksnya:
- Tingkat rinciannya bener nggak? Per transaksi, per struk, atau per pelanggan.
- Rentang tanggalnya nutup periode yang diminta?
- Baris yang harus dibuang udah dibuang? Transaksi batal, akun percobaan, transaksi karyawan.
- Definisi metriknya sama dengan yang dipakai tim lain?
Nomor 4 yang paling sering jadi sumber ribut. "Pelanggan aktif" bisa berarti pernah belanja 30 hari terakhir menurut tim marketing dan 90 hari menurut tim keuangan. Query kamu benar secara teknis, tapi jawabannya beda.
Gimana cara ngecek JOIN nggak gandain baris?
Hitung jumlah baris sebelum dan sesudah JOIN. Kalau tabel kiri punya 3.104 baris dan hasil JOIN jadi 3.418, berarti ada baris yang kepenggandaan. Penyebab paling umum: tabel kanan punya lebih dari satu baris per kunci, misalnya satu pelanggan punya dua alamat.
-- Cek duplikasi kunci di tabel kanan sebelum JOIN
SELECT pelanggan_id, COUNT(*)
FROM alamat
GROUP BY pelanggan_id
HAVING COUNT(*) > 1;
Kalau query di atas ngasih hasil, JOIN kamu bakal gandain baris. Solusinya ambil satu baris per kunci dulu di CTE terpisah, baru di-JOIN.
Jebakan kedua yang sering lolos review: kondisi tabel kanan ditaruh di WHERE pada LEFT JOIN.
| Yang ditulis | Yang terjadi |
|---|---|
LEFT JOIN t ... WHERE t.status = 'selesai' | Berubah jadi INNER JOIN, pelanggan tanpa transaksi hilang |
LEFT JOIN t ... AND t.status = 'selesai' | Tetap LEFT JOIN, pelanggan tanpa transaksi tetap muncul dengan NULL |
Bedanya satu kata, hasilnya beda ratusan baris. Kesalahan sejenis ini aku kumpulin di daftar kesalahan umum SQL pemula.
Penanganan NULL apa yang harus dicek?
Tiga titik: agregat yang ngelewatin NULL, pembagian yang bisa kena nol, dan perbandingan pakai tanda sama dengan. NULL nggak sama dengan apa pun, termasuk NULL lain, jadi WHERE kolom = NULL selalu ngasih nol baris.
| Situasi | Risiko | Perbaikan |
|---|---|---|
AVG(nilai) dengan NULL | Penyebutnya cuma baris terisi | AVG(COALESCE(nilai, 0)) kalau NULL berarti nol |
a / b | Error kalau b nol | a / NULLIF(b, 0) |
WHERE kolom = NULL | Selalu kosong | WHERE kolom IS NULL |
kolom NOT IN (subquery) | Kosong semua kalau subquery punya NULL | Pakai NOT EXISTS |
SUM dari tabel kosong | Hasil NULL, bukan nol | COALESCE(SUM(x), 0) |
Baris keempat itu yang paling jahat karena diamnya total. NOT IN dengan subquery yang mengandung satu NULL aja bakal ngasih nol baris tanpa error apa pun.
Konteks lebih luasnya ada di halaman data quality.
Bagian performa apa yang diperiksa?
Reviewer ngecek apakah query bakal tetap jalan waktu datanya sepuluh kali lipat. Tiga hal yang paling sering jadi masalah: fungsi yang dipasang di kolom yang difilter, SELECT bintang di tabel besar, dan subquery yang jalan per baris.
-- Lambat: fungsi di kolom bikin index nggak kepakai
WHERE DATE(tanggal_transaksi) = '2025-09-06'
-- Cepat: rentang, index tetap kepakai
WHERE tanggal_transaksi >= '2025-09-06'
AND tanggal_transaksi < '2025-09-07'
Empat pemeriksaan cepat:
- Ada fungsi di sisi kiri kondisi WHERE? Tulis ulang jadi rentang.
- SELECT bintang di tabel jutaan baris? Sebutin kolomnya.
- DISTINCT dipakai buat nutupin duplikasi JOIN? Benerin JOIN-nya, jangan tutupin gejalanya.
- Subquery berkorelasi di SELECT? Ganti jadi JOIN atau window function.
Buat mastiin, jalanin EXPLAIN ANALYZE dan lihat mana yang jadi biaya terbesar. Cara bacanya dijelasin di dokumentasi EXPLAIN PostgreSQL.
Kebacaan: apa yang bikin reviewer nyerah duluan
Query yang susah dibaca bikin review jadi dangkal, dan review dangkal cuma nangkep masalah format. Empat hal yang paling nentuin: penamaan alias, pemakaian CTE ketimbang subquery bertingkat, satu kolom per baris di SELECT, dan komentar yang jelasin alasan.
| Hal | Yang bikin susah | Yang bikin enak |
|---|---|---|
| Alias | a, b, t1 | trx, pel, prd |
| Struktur | Subquery 4 lapis | CTE bernama, dibaca atas ke bawah |
| SELECT | 12 kolom dalam 1 baris | 1 kolom per baris |
| Komentar | "ambil data penjualan" | "buang akun QA, dipakai tim uji coba" |
| Nama kolom hasil | col1, jml | jumlah_transaksi, total_nilai |
Aturan lengkapnya ada di SQL style guide. Satu gaya yang dipakai semua orang lebih berguna daripada gaya sempurna yang cuma dipakai satu orang.
Contoh kasus: satu query, tiga masalah
Query di kolom SQL artikel ini datang dari review nyata di dataset toko_berkah punya ngulikdata, 3.104 pelanggan dan 41.892 baris transaksi.
Versi awalnya kelihatan wajar. Tapi hasilnya ngasih 3.418 baris buat 3.104 pelanggan.
Setelah dicek, 219 pelanggan punya lebih dari satu alamat, dan JOIN ke tabel alamat gandain barisnya. Total nilai yang keluar Rp 1.723 juta, padahal angka sebenarnya Rp 1.558 juta.
Selisihnya 10,6 persen. Cukup buat bikin keputusan promo meleset, dan nggak cukup besar buat langsung kelihatan salah.
Masalah kedua: WHERE t.status = 'selesai' bikin 487 pelanggan yang belum pernah transaksi selesai hilang dari hasil, padahal laporannya minta semua pelanggan.
Masalah ketiga: pembagian buat rata-rata nilai bakal error begitu ada pelanggan dengan nol transaksi masuk ke hasil.
Versi perbaikannya nutup ketiganya: alamat diambil satu per pelanggan lewat CTE, filter status dipindah ke dalam CTE transaksi, dan pembagian dibungkus NULLIF.
Cara nyari dan nanganin baris ganda dibahas lebih panjang di panduan deduplikasi data dengan SQL.
Checklist review yang bisa kamu tempel
| Urutan | Yang dicek | Cara cepat |
|---|---|---|
| 1 | Jawab pertanyaan yang bener | Bandingin 1 angka sama sumber lain |
| 2 | Tingkat rincian dan filter | Cek definisi metrik sama tim peminta |
| 3 | Duplikasi baris dari JOIN | Hitung baris sebelum dan sesudah |
| 4 | Kondisi LEFT JOIN di WHERE | Cari nama tabel kanan di klausa WHERE |
| 5 | NULL di agregat dan pembagian | Cari tanda bagi dan NOT IN |
| 6 | Fungsi di kolom yang difilter | Baca ulang semua WHERE |
| 7 | Alias dan struktur CTE | Bisa dibaca atas ke bawah nggak |
| 8 | Komentar alasan | Tiap filter aneh ada penjelasannya |
Nomor 1 sampai 5 wajib. Nomor 6 sampai 8 saran, dan nggak boleh nahan query yang angkanya udah bener.
FAQ
Query buat laporan sekali pakai perlu di-review juga?
Perlu kalau angkanya bakal dipakai buat keputusan atau dikirim ke luar tim. Query sekali pakai punya risiko lebih besar justru karena nggak ada yang ngecek ulang. Buat query eksplorasi yang cuma buat kamu sendiri, review nggak perlu. Patokannya bukan sekali pakai atau nggak, tapi ada yang ambil keputusan dari angkanya atau nggak.
Gimana cara ngasih komentar review yang nggak nyakitin?
Komentari query-nya, bukan orangnya, dan sertakan alasannya. "Ini salah" bikin orang defensif. "JOIN ke alamat bisa gandain baris kalau ada pelanggan yang punya 2 alamat, coba cek jumlah barisnya sebelum dan sesudah" ngasih arah yang jelas. Pisahin juga mana yang wajib dibenerin dan mana yang cuma saran.
Berapa lama waktu wajar buat review satu query?
Sekitar 15 sampai 30 menit buat query 50 sampai 100 baris. Kalau lebih dari sejam, biasanya query-nya kepanjangan dan mendingan diminta pecah jadi beberapa CTE dulu. Review yang buru-buru dalam 3 menit hampir selalu cuma nangkep masalah format, bukan masalah logika.
Perlu jalanin query-nya waktu review atau cukup baca?
Jalanin, minimal bagian pemeriksaan jumlah baris. Baca doang bikin kamu ketinggalan duplikasi baris yang cuma kelihatan dari angka. Kalau nggak bisa akses datanya, minta penulis query nyertain hasil pemeriksaan: jumlah baris sebelum dan sesudah JOIN, plus perbandingan total sama angka dari sumber lain.
Tool apa yang bisa bantu review SQL otomatis?
SQLFluff buat cek format dan aturan penulisan, populer di tim yang pakai dbt. Buat performa, EXPLAIN ANALYZE bawaan database kamu udah cukup. Tapi tool cuma nangkep format dan biaya eksekusi. Kebenaran logika, duplikasi baris, dan penanganan NULL tetap harus dicek manusia yang ngerti datanya.
Yang perlu kamu bawa ke review berikutnya
Dua pemeriksaan yang paling sering nyelametin angka: hitung baris sebelum dan sesudah JOIN, lalu cari nama tabel kanan di klausa WHERE.
Dua itu doang udah nutup mayoritas kesalahan yang aku temui.
Ambil query terakhir yang kamu tulis, jalanin dua pemeriksaan itu sekarang. Sepuluh menit, dan kemungkinan besar kamu nemu satu hal yang perlu dibenerin.
Kalau timmu belum punya aturan penulisan yang disepakati, mulai dari SQL style guide.
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.