Deteksi Outlier dengan SQL: IQR dan Z-Score Tanpa Python
Blog/Tutorial SQL/Deteksi Outlier dengan SQL: IQR dan Z-Score Tanpa Python

Deteksi Outlier dengan SQL: IQR dan Z-Score Tanpa Python

BimaBima
·1 Juni 2026·12 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

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.

Apa itu 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.

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.

Metode 1: IQR — andalan buat data bisnis

IQR (Interquartile Range) itu rentang antara kuartil 1 dan kuartil 3 — alias 50% data yang di tengah.

Aturan mainnya:

  • Q1 = nilai di persentil ke-25
  • Q3 = nilai di persentil ke-75
  • IQR = Q3 − Q1
  • Outlier = nilai di bawah Q1 − 1,5 × IQR atau di atas Q3 + 1,5 × IQR

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:

WITH kuartil AS (
  SELECT
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY total_bayar) AS q1,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY total_bayar) AS q3
  FROM transaksi
),
batas AS (
  SELECT
    q1,
    q3,
    q3 - q1 AS iqr,
    q1 - 1.5 * (q3 - q1) AS batas_bawah,
    q3 + 1.5 * (q3 - q1) AS batas_atas
  FROM kuartil
)
SELECT
  t.no_invoice,
  t.tanggal,
  t.cabang,
  t.total_bayar,
  b.batas_atas
FROM transaksi t
CROSS JOIN batas b
WHERE t.total_bayar > b.batas_atas
   OR t.total_bayar < b.batas_bawah
ORDER BY t.total_bayar DESC;

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.

Kenapa IQR lebih aman?

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.

Metode 2: Z-Score — kalau distribusinya normal

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.

WITH stats AS (
  SELECT
    AVG(total_bayar) AS rata2,
    STDDEV(total_bayar) AS sd
  FROM transaksi
)
SELECT
  t.no_invoice,
  t.total_bayar,
  ROUND((t.total_bayar - s.rata2) / s.sd, 2) AS z_score
FROM transaksi t
CROSS JOIN stats s
WHERE ABS((t.total_bayar - s.rata2) / s.sd) > 3
ORDER BY ABS((t.total_bayar - s.rata2) / s.sd) DESC;

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.

SELECT
  AVG(total_bayar) AS mean,
  PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY total_bayar) AS median
FROM transaksi;

Kalau mean-nya jauh lebih gede dari median, datamu miring ke kanan. Pakai IQR.

Metode 3: IQR per grup — yang paling sering kepake

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.

WITH batas_cabang AS (
  SELECT
    cabang,
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY total_bayar) AS q1,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY total_bayar) AS q3
  FROM transaksi
  GROUP BY cabang
)
SELECT
  t.cabang,
  t.no_invoice,
  t.tanggal,
  t.total_bayar,
  ROUND(b.q3 + 1.5 * (b.q3 - b.q1), 0) AS batas_cabang
FROM transaksi t
JOIN batas_cabang b ON t.cabang = b.cabang
WHERE t.total_bayar > b.q3 + 1.5 * (b.q3 - b.q1)
ORDER BY t.cabang, t.total_bayar DESC;

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.

Contoh kasus: 12.400 transaksi toko_berkah

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: Rp 148.000
  • Median: Rp 112.000
  • Q1: Rp 61.000
  • Q3: Rp 186.000
  • IQR: Rp 125.000
  • Batas atas: Rp 186.000 + 1,5 × 125.000 = Rp 373.500

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.

Yang paling menarik dari ini

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.

Kesalahan umum waktu deteksi outlier

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.

Bikin query-nya jadi alarm harian

Cara paling gampang: bikin view, lalu jadwalin dicek tiap pagi.

CREATE VIEW v_outlier_harian AS
WITH batas_cabang AS (
  SELECT
    cabang,
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY total_bayar) AS q1,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY total_bayar) AS q3
  FROM transaksi
  WHERE tanggal >= CURRENT_DATE - INTERVAL '90 days'
  GROUP BY cabang
)
SELECT
  t.tanggal,
  t.cabang,
  t.no_invoice,
  t.total_bayar,
  ROUND(b.q3 + 1.5 * (b.q3 - b.q1), 0) AS batas
FROM transaksi t
JOIN batas_cabang b ON t.cabang = b.cabang
WHERE t.tanggal = CURRENT_DATE - 1
  AND t.total_bayar > b.q3 + 1.5 * (b.q3 - b.q1);

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.

FAQ

Apa itu outlier dalam data?

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.

Lebih baik pakai IQR atau Z-Score?

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.

Berapa batas Z-Score untuk outlier?

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.

Apakah outlier harus selalu dihapus?

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.

Fungsi SQL apa yang dipakai buat hitung kuartil?

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.

Penutup

Tiga hal yang perlu kamu bawa.

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.

Coba Langsung

Mau praktek langsung? Mulai latihan SQL gratis

Latihan interaktif, langsung di browser.

Buka NgulikSQL →
Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel Terkait

7 SQL Client Gratis Terbaik buat Analis Data (2026)
Tutorial SQL
10 Juli 2026•9 menit baca

7 SQL Client Gratis Terbaik buat Analis Data (2026)

Nggak perlu bayar buat nulis query. Ini 7 SQL client gratis yang beneran dipakai analis, plus kelebihan dan kekurangannya masing-masing.

BimaBima
SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim
Tutorial SQL
7 Juli 2026•9 menit baca

SQL Style Guide: Cara Nulis Query yang Enak Dibaca Tim

Sepuluh aturan SQL style guide yang bikin query kamu kebaca sama tim — dan sama kamu sendiri 6 bulan lagi. Lengkap dengan contoh sebelum-sesudah.

BimaBima
Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya
Tutorial SQL
4 Juli 2026•11 menit baca

Take-Home Test SQL Data Analyst: Contoh Soal + Cara Ngerjainnya

Contoh soal take-home test SQL yang beneran dipakai perusahaan, dikerjain step by step — dari baca soal, nulis query, sampai nyusun insight yang bikin recruiter nengok.

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

Copyright © 2026 - All rights reserved

LINKS
SupportPricingDatasetBlogAffiliates
LEGAL
Terms of servicesPrivacy policy
Ngulik Data
DatasetLeaderboardBlogStore