TL;DR
Deteksi outlier dengan SQL bisa pakai dua metode: IQR, yang nandain nilai di luar rentang Q1 dikurangi 1,5 kali IQR sampai Q3 ditambah 1,5 kali IQR, dan Z-Score, yang nandain nilai yang jaraknya lebih dari 3 standar deviasi dari rata-rata. IQR lebih aman buat data yang miring karena pakai median, sementara Z-Score cuma cocok kalau distribusinya mendekati normal. Dua-duanya bisa dijalanin dengan window function, tanpa Python.
Deteksi outlier gak butuh Python. IQR dan Z-Score dua-duanya bisa jalan di SQL, dan buat mayoritas kasus bisnis itu udah cukup.
Keuntungannya lumayan: kamu gak perlu narik data keluar dari database, gak perlu setup environment, dan query-nya bisa dijadwalin jalan tiap hari.
Di dataset toko_berkah, satu query IQR nangkep transaksi Rp 47.000.000 yang harusnya Rp 470.000. Kasir salah pencet nol dua kali. Angka itu bikin rata-rata transaksi harian cabang itu naik 34%. Dan hampir jadi dasar target bulan berikutnya.
Outlier adalah nilai yang jaraknya jauh dari sebagian besar nilai lain di kolom yang sama.
Kalau 12.000 transaksi tokomu rata-rata Rp 135 ribu, dan ada satu yang Rp 47 juta, itu outlier.
Yang penting: outlier gak selalu salah. Bisa jadi itu pesanan grosir dari pelanggan korporat, dan itu kejadian nyata yang justru penting.
Makanya urutannya selalu: deteksi dulu, cek satu-satu, baru mutusin. Bukan langsung hapus.
IQR (Interquartile Range) itu rentang antara kuartil 1 dan kuartil 3, alias 50% data yang di tengah.
Aturan mainnya:
Angka 1,5 itu konvensi dari John Tukey, dan sampai sekarang masih standar. Kalau mau lebih ketat, pakai 3, itu batas "outlier ekstrem".
Query-nya:
CROSS JOIN di sini aman, tabel batas cuma punya 1 baris, jadi tiap transaksi cuma dipasangin sama satu set batas.
PERCENTILE_CONT ada di PostgreSQL, BigQuery, Snowflake, dan SQL Server. Sintaks lengkapnya bisa kamu cek di dokumentasi fungsi agregat PostgreSQL.
Karena dia pakai median dan kuartil, dua ukuran yang gak gampang ketarik nilai ekstrem.
Bandingin sama Z-Score yang pakai rata-rata. Kalau ada satu transaksi Rp 47 juta di data, rata-ratanya ikut naik, standar deviasinya ikut membengkak, dan outlier-nya jadi nyembunyiin dirinya sendiri.
Data penjualan hampir selalu miring ke kanan. Banyak transaksi kecil, sedikit transaksi besar. IQR nanganin itu dengan baik. Z-Score nggak.
Z-Score ngukur berapa standar deviasi jarak sebuah nilai dari rata-rata.
Rumusnya: z = (nilai − rata-rata) / standar_deviasi
Batas yang umum: |z| > 3. Di distribusi normal, cuma sekitar 0,3% data yang jatuh di luar situ.
Kapan ini cocok? Kalau distribusi datamu mendekati normal: tinggi badan, skor ujian, waktu proses produksi.
Kapan ini gak cocok? Data penjualan, gaji, jumlah follower, durasi kunjungan. Semuanya miring, dan Z-Score bakal ngasih hasil yang menyesatkan.
Cek dulu bentuk distribusinya sebelum milih metode. Cara cepat: bandingin mean dan median.
Kalau mean-nya jauh lebih gede dari median, datamu miring ke kanan. Pakai IQR.
Ini yang jarang dibahas, tapi paling berguna di praktik.
Masalahnya begini. Cabang di kawasan perkantoran rata-rata transaksinya Rp 45 ribu. Cabang di kawasan perumahan Rp 220 ribu. Kalau kamu itung outlier secara global, semua transaksi cabang perumahan bakal ketangkep sebagai "outlier".
Padahal mereka normal, buat cabangnya sendiri.
Sekarang tiap transaksi dibandingin sama batas cabangnya sendiri. Jauh lebih adil, dan jauh lebih sedikit false positive.
Prinsip yang sama bisa kamu pakai per kategori produk, per bulan, atau per segmen pelanggan.
Data penjualan 6 toko kelontong di Bekasi, Januari sampai Maret 2026. Setelah dibersihin dari duplikat (detailnya di artikel cara menghapus data duplikat di SQL) tersisa 11.282 baris bersih.
Statistik dasarnya:
Mean jauh di atas median. Datanya miring ke kanan, persis seperti dugaan. IQR jadi pilihan yang bener.
Query IQR nangkep 218 transaksi di atas batas (1,9% dari total). Aku periksa satu-satu, dan mereka jatuh ke tiga kelompok:
Kelompok 1: salah input (7 transaksi). Yang paling parah: Rp 47.000.000 buat 3 item belanjaan. Kasir kelebihan dua nol. Transaksi lain di jam yang sama nunjukin pola belanja biasa. Ini beneran error, dan diperbaiki jadi Rp 470.000.
Kelompok 2: pesanan grosir (183 transaksi). Nilai Rp 400 ribu sampai Rp 2,8 juta. Semuanya dari 24 pelanggan yang sama, yang belanja rutin tiap 1-2 minggu. Ternyata mereka pemilik warung kecil yang kulakan di toko_berkah.
Kelompok 3: belanja Ramadan (28 transaksi). Semuanya di minggu terakhir Maret, nilai Rp 380 ribu sampai Rp 900 ribu. Belanja persiapan puasa. Normal, cuma musiman.
Kelompok 2 itu bukan masalah. Itu peluang.
24 pelanggan itu cuma 0,4% dari total pelanggan. Tapi mereka nyumbang 11,3% dari total omzet kuartal.
Dan gak ada yang tau mereka ada. Mereka gak pernah muncul di laporan, karena laporan cuma nampilin agregat.
Kalau outlier-nya langsung dihapus "biar datanya bersih", segmen kulakan ini ilang dari radar selamanya. Padahal ini kandidat kuat buat program harga grosir.
Itu poin utama dari artikel ini: outlier adalah tempat insight paling sering ngumpet.
1. Langsung hapus tanpa dicek. Ini cara paling cepat ngilangin insight paling berharga di datamu. Selalu periksa dulu.
2. Pakai Z-Score di data yang miring. Outlier gede bikin standar deviasi membengkak, dan akhirnya dia nyembunyiin dirinya sendiri. Cek mean vs median dulu.
3. Deteksi outlier secara global padahal grupnya beda-beda. Cabang perkantoran dan perumahan punya pola belanja beda. Deteksi per grup.
4. Lupa nanganin NULL. AVG dan STDDEV ngabaikan NULL, tapi COUNT(*) nggak. Persentase outlier kamu bisa salah. Cek jumlah NULL dulu.
5. Cuma lihat outlier atas. Transaksi Rp 500 juga aneh kalau median-nya Rp 112 ribu. Bisa jadi itu retur yang salah catat, atau item yang harganya lupa diisi.
6. Deteksi sekali, terus lupa. Bikin query-nya jadi cek rutin harian. Kalau ada transaksi aneh masuk hari ini, kamu tau besok pagi, bukan tiga bulan lagi pas tutup buku.
Cara paling gampang: bikin view, lalu jadwalin dicek tiap pagi.
Perhatikan batasnya dihitung dari data 90 hari terakhir, bukan seluruh riwayat. Jadi kalau pola belanja berubah pelan-pelan, batasnya ikut menyesuaikan.
Buat lebih dalam soal window function yang dipakai di sini, ada halaman PERCENTILE_CONT dan glossary outlier.
Outlier adalah nilai yang jaraknya jauh dari sebagian besar nilai lain di kolom yang sama. Kalau 12.000 transaksi tokomu rata-rata Rp 135 ribu dan ada satu yang Rp 47 juta, itu outlier. Outlier bisa berupa kesalahan input, tapi bisa juga kejadian nyata yang penting, misalnya pesanan grosir. Makanya gak boleh langsung dihapus.
IQR lebih aman buat kebanyakan data bisnis. IQR pakai median dan kuartil yang gak gampang ketarik nilai ekstrem, sementara Z-Score pakai rata-rata dan standar deviasi yang justru ikut membengkak kalau ada outlier besar. Data penjualan hampir selalu miring ke kanan, jadi IQR lebih cocok. Pakai Z-Score cuma kalau distribusinya mendekati normal.
Batas paling umum adalah 3: nilai yang jaraknya lebih dari 3 standar deviasi dari rata-rata dianggap outlier. Di distribusi normal, cuma sekitar 0,3% data yang jatuh di luar batas itu. Ada yang pakai batas 2 kalau mau lebih sensitif, tapi hasilnya jadi banyak false positive.
Nggak. Menghapus outlier tanpa dicek itu cara paling cepat ngilangin insight paling berharga di datamu. Cek dulu apakah itu kesalahan input, kalau iya, perbaiki. Kalau ternyata kejadian nyata kayak pesanan grosir, jangan dihapus, tapi pisahin analisisnya. Yang penting kamu tau kenapa nilai itu ada.
PERCENTILE_CONT yang paling umum, dipakai dengan format PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY kolom) buat dapetin Q1. Ada di PostgreSQL, BigQuery, Snowflake, dan SQL Server. MySQL versi lama gak punya ini. Alternatifnya PERCENTILE_DISC, yang ngambil nilai asli dari data bukan hasil interpolasi.
Pakai IQR buat data bisnis, Z-Score cuma kalau distribusinya normal. Cek mean vs median buat tau yang mana.
Deteksi per grup, bukan global. Cabang yang beda punya pola yang beda.
Dan jangan hapus outlier sebelum kamu ngerti kenapa dia ada. Di toko_berkah, 183 dari 218 outlier ternyata segmen pelanggan kulakan yang nyumbang 11,3% omzet, dan mereka gak pernah muncul di laporan mana pun.
Mau latihan query kayak gini pakai data beneran? Mulai dari panduan belajar SQL dari nol, dataset toko kelontong Indonesia bisa langsung kamu utak-atik.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Analisa per kuartal, hari kerja, atau musim jadi ribet kalau tiap query ngitung ulang atribut tanggal. Tabel kalender nyimpen semua atribut itu sekali, biar tinggal di-JOIN.
Laporan penjualan harian sering bolong di hari tanpa transaksi. Ini cara bikin deret tanggal lengkap di SQL biar tiap hari muncul, walau nilainya nol.
Struktur organisasi tersimpan sebagai kolom id_atasan yang saling nunjuk. Ini cara narik rantai jabatan, hitung total bawahan, dan span of control cuma pakai SQL.