6 Dimensi Kualitas Data dan Cara Mengukurnya dengan Query
Blog/Tutorial SQL/6 Dimensi Kualitas Data dan Cara Mengukurnya dengan Query

6 Dimensi Kualitas Data dan Cara Mengukurnya dengan Query

BimaBima
·21 Desember 2025·8 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Enam dimensi kualitas data yang umum dipakai: completeness, uniqueness, validity, consistency, accuracy, dan timeliness. Tiap dimensi bisa diukur jadi persentase pakai satu query SQL yang ngebandingin baris lolos dengan total baris. Jalanin semuanya tiap hari, simpan hasilnya ke tabel skor, lalu pasang ambang batas biar kamu tau angkanya turun sebelum stakeholder yang ngasih tau.

Kualitas data diukur lewat enam dimensi: completeness, uniqueness, validity, consistency, accuracy, dan timeliness. Tiap dimensi bisa diubah jadi satu angka persentase pakai satu query SQL.

Yang bikin banyak tim mandek: kualitas data dianggap perasaan. "Datanya kotor" itu keluhan, bukan ukuran.

Begitu kamu punya enam angka yang dicatat tiap hari, obrolannya berubah. Dari "kayaknya ada yang salah" jadi "completeness kolom nama pelanggan turun dari 98% ke 71% sejak Kamis".

Semua query di bawah pakai tabel transaksi dari dataset toko_berkah, 48.310 baris penjualan grosir sepanjang 2025. Sintaksnya PostgreSQL, tapi gampang disesuaikan.

Apa itu dimensi kualitas data?

Dimensi kualitas data adalah sudut pengukuran yang dipakai buat menilai apakah satu tabel layak dipakai buat ambil keputusan. Kerangka enam dimensi ini dipopulerkan DAMA UK dan dipakai di banyak program data quality. Tiap dimensi ngecek hal yang beda, dan tabel bisa lolos di satu dimensi tapi jeblok di dimensi lain.

Contohnya tabel yang 100% lengkap tanpa satu pun sel kosong, tapi 30% barisnya duplikat. Completeness sempurna, uniqueness hancur.

Makanya keenamnya diukur terpisah. Satu angka gabungan malah nyembunyiin masalah.

1. Completeness: berapa banyak yang kosong?

Completeness ngukur persentase baris yang punya isi di kolom yang wajib diisi. Kolom NULL di kolom kunci bikin agregasi kamu ngitung penyebut yang salah, dan efeknya nyebar ke semua laporan turunan.

SELECT
  ROUND(100.0 * COUNT(nama_pelanggan) / COUNT(*), 2) AS pct_nama_lengkap,
  ROUND(100.0 * COUNT(id_cabang)     / COUNT(*), 2) AS pct_cabang_lengkap,
  ROUND(100.0 * COUNT(qty)           / COUNT(*), 2) AS pct_qty_lengkap
FROM transaksi;

COUNT(kolom) nggak ngitung NULL, sedangkan COUNT(*) ngitung semua baris. Selisih keduanya = jumlah yang kosong.

Hati-hati sama string kosong. Di banyak sistem, sel yang keliatan kosong isinya '', bukan NULL, dan COUNT tetap ngitungnya sebagai ada isi:

SELECT COUNT(*) AS kosong_terselubung
FROM transaksi
WHERE nama_pelanggan IS NULL
   OR TRIM(nama_pelanggan) = ''
   OR UPPER(TRIM(nama_pelanggan)) IN ('N/A', 'NULL', '-');

Di toko_berkah, cek pertama bilang completeness nama pelanggan 96,8%. Setelah pola "kosong terselubung" ikut dihitung, angkanya jatuh ke 88,2%. Selisih 8,6 poin itu isinya tulisan "-" dan "N/A".

2. Uniqueness: ada berapa baris dobel?

Uniqueness ngukur persentase baris yang nggak kembar. Baris dobel bikin total penjualan kelihatan lebih besar dari kenyataan, dan ini jenis kesalahan yang paling jarang ketahuan karena angkanya tetap masuk akal.

SELECT
  COUNT(*)                          AS total_baris,
  COUNT(DISTINCT id_transaksi)      AS id_unik,
  COUNT(*) - COUNT(DISTINCT id_transaksi) AS dobel
FROM transaksi;

Buat lihat siapa pelakunya:

SELECT id_transaksi, COUNT(*) AS jumlah
FROM transaksi
GROUP BY id_transaksi
HAVING COUNT(*) > 1
ORDER BY jumlah DESC
LIMIT 20;

Duplikat yang lebih licik adalah yang ID-nya beda tapi isinya sama persis. Biasanya muncul gara-gara satu file di-import dua kali:

SELECT tanggal, id_pelanggan, id_produk, qty, total, COUNT(*) AS jumlah
FROM transaksi
GROUP BY tanggal, id_pelanggan, id_produk, qty, total
HAVING COUNT(*) > 1;

Cara ini nemuin 1.204 baris kembar di toko_berkah, semuanya dari satu tanggal impor di bulan Maret. Nilainya Rp 47,3 juta yang kehitung dua kali.

3. Validity: formatnya sesuai aturan nggak?

Validity ngukur berapa persen nilai yang masuk akal menurut aturan yang kamu tetapkan. Qty nggak boleh negatif, harga nggak boleh nol, email harus ada tanda @, kode pos Indonesia harus 5 digit.

SELECT
  ROUND(100.0 * SUM(CASE WHEN qty > 0 THEN 1 ELSE 0 END) / COUNT(*), 2) AS pct_qty_valid,
  ROUND(100.0 * SUM(CASE WHEN harga_satuan > 0 THEN 1 ELSE 0 END) / COUNT(*), 2) AS pct_harga_valid,
  ROUND(100.0 * SUM(CASE WHEN tanggal <= CURRENT_DATE THEN 1 ELSE 0 END) / COUNT(*), 2) AS pct_tanggal_valid
FROM transaksi;

Pola SUM(CASE WHEN ... THEN 1 ELSE 0 END) itu yang paling sering kepakai. Dia ngitung baris yang lolos syarat, lalu dibagi total.

Buat kolom teks, pakai pencocokan pola:

SELECT COUNT(*) AS kode_pos_ngaco
FROM pelanggan
WHERE kode_pos !~ '^[0-9]{5}$';

Tanggal masa depan itu tanda bahaya yang sering kelewat. 43 transaksi di toko_berkah bertanggal 2026 padahal datanya ditarik November 2025. Semuanya salah ketik tahun waktu input manual.

4. Consistency: nyambung nggak antar tabel?

Consistency ngukur apakah data yang sama di tempat berbeda saling cocok. Yang paling sering bocor: baris yatim, yaitu transaksi yang nunjuk ke ID pelanggan yang nggak ada di tabel master.

SELECT COUNT(*) AS transaksi_yatim
FROM transaksi t
LEFT JOIN pelanggan p ON t.id_pelanggan = p.id_pelanggan
WHERE p.id_pelanggan IS NULL;

Kalau angkanya nggak nol, tiap laporan yang pakai INNER JOIN ke tabel pelanggan bakal diam-diam ngebuang baris itu. Total penjualan di dashboard kamu jadi lebih kecil dari kenyataan tanpa error apa pun.

Bentuk lain: satu angka dihitung dua tempat dan hasilnya beda.

SELECT
  (SELECT SUM(total) FROM transaksi WHERE EXTRACT(MONTH FROM tanggal) = 10) AS dari_transaksi,
  (SELECT SUM(nilai) FROM rekap_bulanan WHERE bulan = '2025-10') AS dari_rekap;

Selisih di sini artinya salah satu tabel ketinggalan proses. Cek ini yang paling sering nyelametin aku sebelum kirim laporan.

5. Accuracy: angkanya bener nggak?

Accuracy ngukur apakah nilai di tabel cocok dengan kenyataan. Ini dimensi paling susah, soalnya butuh pembanding di luar database.

Cara paling praktis: pakai aturan internal yang harus selalu benar.

SELECT
  id_transaksi, qty, harga_satuan, total,
  qty * harga_satuan AS seharusnya,
  total - (qty * harga_satuan) AS selisih
FROM transaksi
WHERE ABS(total - (qty * harga_satuan)) > 1
ORDER BY ABS(total - (qty * harga_satuan)) DESC;

Toleransi 1 rupiah dipasang buat nampung pembulatan. Di toko_berkah, 318 baris gagal cek ini. Setelah ditelusuri, semuanya transaksi dengan diskon yang dipotong dari total tapi nggak dicatat di kolom mana pun.

Itu bukan salah hitung. Itu kolom yang hilang. Cek accuracy sering nemuin masalah desain tabel, bukan cuma angka nyasar.

Cek lain yang murah: cari outlier ekstrem yang secara bisnis nggak mungkin.

SELECT id_transaksi, qty, total
FROM transaksi
WHERE qty > 1000 OR total > 500000000;

6. Timeliness: datanya masih baru?

Timeliness ngukur seberapa baru data yang ada. Laporan yang jalan mulus di atas data tiga hari lalu tetap salah, dan biasanya nggak ada yang nyadar sampai ada yang protes.

SELECT
  MAX(tanggal) AS transaksi_terakhir,
  CURRENT_DATE - MAX(tanggal) AS umur_hari,
  CASE WHEN CURRENT_DATE - MAX(tanggal) > 1 THEN 'BASI' ELSE 'OK' END AS status
FROM transaksi;

Cek juga sebaran per hari, biar ketahuan kalau ada tanggal yang bolong:

SELECT tanggal, COUNT(*) AS jumlah_baris
FROM transaksi
WHERE tanggal >= CURRENT_DATE - 14
GROUP BY tanggal
ORDER BY tanggal;

Hari yang jumlah barisnya jauh di bawah biasanya artinya proses muat datanya gagal separuh jalan. Ini lebih bahaya daripada gagal total, soalnya nggak ada alarm yang bunyi.

Gabungin jadi satu tabel skor

Enam query terpisah nggak kepakai kalau harus dijalanin manual. Gabung jadi satu, lalu simpan hasilnya.

INSERT INTO skor_kualitas (tanggal_cek, dimensi, tabel_dicek, skor)
SELECT CURRENT_DATE, 'completeness', 'transaksi',
       ROUND(100.0 * COUNT(nama_pelanggan) / COUNT(*), 2) FROM transaksi
UNION ALL
SELECT CURRENT_DATE, 'uniqueness', 'transaksi',
       ROUND(100.0 * COUNT(DISTINCT id_transaksi) / COUNT(*), 2) FROM transaksi
UNION ALL
SELECT CURRENT_DATE, 'validity', 'transaksi',
       ROUND(100.0 * SUM(CASE WHEN qty > 0 AND harga_satuan > 0 THEN 1 ELSE 0 END) / COUNT(*), 2) FROM transaksi;

Jadwalin sekali sehari setelah proses muat data selesai. Habis itu bikin query pembanding sama hari sebelumnya:

SELECT dimensi, skor,
       LAG(skor) OVER (PARTITION BY dimensi ORDER BY tanggal_cek) AS skor_kemarin,
       skor - LAG(skor) OVER (PARTITION BY dimensi ORDER BY tanggal_cek) AS perubahan
FROM skor_kualitas
WHERE tanggal_cek >= CURRENT_DATE - 7
ORDER BY dimensi, tanggal_cek;

Buat sintaks lengkap fungsi window kayak LAG, lihat dokumentasi resmi PostgreSQL.

Tempel hasilnya ke dashboard internal kamu. Enam angka, satu baris per hari.

Tabel ringkas enam dimensi

DimensiPertanyaannyaKunci SQLAmbang usulan
CompletenessAda yang kosong?COUNT(kolom) / COUNT(*)≥ 99%
UniquenessAda yang dobel?COUNT(DISTINCT) / COUNT(*)100%
ValidityFormatnya sesuai aturan?SUM(CASE WHEN)≥ 98%
ConsistencyNyambung antar tabel?LEFT JOIN ... IS NULL0 baris yatim
AccuracyAngkanya bener?Cek aturan hitung≥ 99,5%
TimelinessMasih baru?CURRENT_DATE - MAX(tanggal)≤ 1 hari

Kesalahan umum waktu ngukur kualitas data

Cuma ngecek NULL, lupa string kosong. Ini yang bikin completeness toko_berkah kelihatan 8,6 poin lebih bagus dari kenyataan.

Skornya nggak disimpan. Angka hari ini nggak berarti tanpa angka minggu lalu. Tanpa riwayat, kamu cuma bisa nangkep kerusakan besar, bukan penurunan pelan.

Ngecek semua kolom dengan bobot sama. Kolom total yang bolong itu darurat. Kolom catatan yang bolong itu wajar. Pilih 5-10 kolom yang beneran dipakai di laporan, lalu ukur itu aja.

Ambang batasnya nggak ditulis. Kalau nggak ada angka yang disepakati duluan, setiap skor jelek bakal dinegosiasikan jadi "masih oke kok".

Nemu masalah tapi nggak dicatat sumbernya. 1.204 duplikat di toko_berkah bakal balik lagi bulan depan kalau proses impornya nggak dibenerin. Ukuran tanpa perbaikan cuma nambah kerjaan.

FAQ

Dimensi mana yang harus dicek duluan?

Mulai dari completeness dan uniqueness. Dua ini paling gampang diukur dan paling sering jadi biang angka yang salah. Kolom kosong bikin agregasi kamu ngitung penyebut yang keliru, dan baris dobel bikin total penjualan kelihatan lebih besar dari kenyataan. Setelah dua itu bersih, baru lanjut ke validity dan consistency.

Berapa persen skor kualitas data yang dianggap aman?

Tergantung dampaknya. Buat kolom yang dipakai di laporan keuangan, aku pasang ambang 99,5% dan angka di bawah itu langsung dicek. Buat kolom deskriptif kayak catatan atau kategori sekunder, 90% masih bisa dipakai. Yang penting ambangnya ditulis, bukan ditebak tiap kali angkanya jelek.

Perlu tool khusus kayak Great Expectations?

Nggak buat mulai. Enam query di artikel ini plus satu tabel penampung skor udah cukup buat tim kecil. Tool khusus baru masuk akal kalau jumlah tabel yang dicek udah puluhan, atau kamu butuh hasil pengecekannya otomatis nge-block pipeline waktu gagal.

Gimana ngukur accuracy kalau nggak punya sumber pembanding?

Pakai aturan internal yang harus selalu benar. Contohnya total = qty dikali harga satuan, atau jumlah semua cabang harus sama dengan total nasional. Aturan begini nggak butuh sumber luar dan tetap nangkep sebagian besar salah hitung. Buat kolom yang nggak punya aturan begitu, ambil sampel 30 baris dan cek manual ke dokumen aslinya.

Seberapa sering query kualitas data harus dijalanin?

Sehari sekali, tepat setelah proses muat data selesai. Kalau dijalanin sebelum data masuk, kamu ngukur kondisi kemarin. Simpan hasilnya ke tabel dengan kolom tanggal, biar kamu bisa lihat trennya. Penurunan pelan selama dua minggu lebih berbahaya daripada satu hari yang jeblok, dan cuma kelihatan kalau riwayatnya disimpan.

Langkah pertama hari ini

Ambil satu tabel yang paling sering dipakai di kantor kamu. Jalanin query completeness dan uniqueness di atas. Dua query, lima menit.

Kalau salah satunya di bawah 95%, kamu baru aja nemu alasan kenapa laporan bulanan kamu sering nggak cocok sama catatan tim lain.

Simpan hasilnya ke satu tabel skor, lalu ulangi besok. Riwayat itu yang bikin angkanya berguna.

Kalau kamu lagi nyusun cara kerja tim data yang rapi juga, lanjut ke bikin SLA untuk tim data satu orang.

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

Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Tutorial SQL
19 Juli 2026•10 menit baca

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.

BimaBima
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
Tutorial SQL
17 Juli 2026•9 menit baca

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.

BimaBima
Gap and Island Analysis di SQL
Tutorial SQL
15 Juli 2026•10 menit baca

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.

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.

© 2026 Ngulik Data. Semua hak dilindungi.

TAUTAN
BantuanHargaDatasetBlogAfiliasi
LEGAL
Syarat & KetentuanKebijakan Privasi
Ngulik Data
DatasetLeaderboardBlogStore