Anonimisasi dan Pseudonimisasi Data Pelanggan di SQL
Blog/Tutorial SQL/Anonimisasi dan Pseudonimisasi Data Pelanggan di SQL

Anonimisasi dan Pseudonimisasi Data Pelanggan di SQL

BimaBima
·2 Desember 2025·11 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

TL;DR

Pseudonimisasi ngganti identitas asli dengan kode yang masih bisa dibalik kalau kamu punya kuncinya, misalnya hashing nomor HP dengan garam rahasia. Anonimisasi menghapus kemungkinan itu sepenuhnya, biasanya lewat generalisasi dan penghapusan baris yang terlalu unik. Di SQL, alurnya: pisahkan kolom identitas langsung, terapkan hashing atau masking, generalisasi kolom kuasi-identitas kayak tanggal lahir dan kode pos, lalu cek ulang apakah masih ada kombinasi yang cuma dimiliki satu orang.

Hapus kolom nama, lalu bilang datanya udah aman. Ini yang paling sering aku lihat, dan ini yang paling sering jebol.

Kombinasi tanggal lahir, jenis kelamin, dan kode pos sering cukup buat nunjuk ke satu orang. Kolom nama cuma satu pintu dari banyak pintu.

Di bawah ini teknik anonimisasi dan pseudonimisasi yang bisa kamu jalankan langsung di SQL, plus query buat ngecek apakah hasilnya beneran aman.

Apa bedanya anonimisasi dan pseudonimisasi?

Pseudonimisasi ngganti identitas asli dengan kode pengganti, tapi kaitannya masih bisa dibalik kalau kamu punya kunci atau tabel pemetaannya. Anonimisasi menutup kemungkinan itu sepenuhnya, jadi nggak ada jalan balik ke individu aslinya, bahkan buat kamu sendiri.

Bedanya penting karena beda kegunaan.

PseudonimisasiAnonimisasi
Bisa dibalik?Bisa, kalau punya kunciNggak bisa
Bisa dipakai JOIN antar tabel?BisaBiasanya nggak
Bisa lacak perilaku satu orang lintas waktu?BisaNggak
Cocok buatAnalisa internal, cohort, retensiDataset yang dibagikan keluar
ContohHash nomor HP dengan garamRekap per kecamatan tanpa baris individu

Kesalahan yang sering muncul: nyebut data yang udah di-hash sebagai "anonim". Kalau kamu masih pegang garamnya, itu masih pseudonim.

Buat analisa yang butuh ngikutin satu pelanggan lintas bulan, misalnya cohort analysis, kamu butuh pseudonimisasi. Anonimisasi bakal ngerusak analisanya.

Kolom apa aja yang perlu ditangani?

Bagi jadi tiga jenis. Penanganannya beda.

Identitas langsung. Nama, NIK, nomor HP, email, nomor rekening, plat nomor. Ini yang harus dihapus atau diganti kode.

Kuasi-identitas. Tanggal lahir, kode pos, kecamatan, jabatan, tanggal transaksi pertama. Sendirian nggak nunjuk siapa-siapa, tapi digabung bisa. Ini yang harus digeneralisasi.

Data sensitif. Riwayat penyakit, penghasilan, agama, catatan kredit. Ini yang paling merugikan kalau bocor, dan justru sering jadi kolom yang mau dianalisa.

Bikin daftarnya dulu sebelum nulis query apa pun. Aku biasanya taruh di satu tabel dokumentasi dengan kolom nama_kolom, jenis, dan tindakan.

Gimana cara pseudonimisasi nomor HP di SQL?

Pakai hashing dengan garam rahasia. Garam itu string acak yang kamu tambahin sebelum di-hash, dan disimpan terpisah dari datanya.

Di PostgreSQL, aktifin dulu ekstensinya:

CREATE EXTENSION IF NOT EXISTS pgcrypto;

Lalu hash-nya:

SELECT
  encode(digest(no_hp || current_setting('app.salt'), 'sha256'), 'hex') AS id_pelanggan_semu,
  kota,
  total_belanja
FROM pelanggan;

Hasilnya string 64 karakter yang sama tiap kali nomor yang sama diproses. Jadi JOIN antar tabel tetap jalan.

Kenapa garamnya wajib? Karena nomor HP Indonesia jumlah kemungkinannya terbatas. Siapa pun bisa hitung SHA-256 dari semua nomor yang mungkin, lalu cocokkan satu per satu. Hash tanpa garam sama sekali nggak nutupin apa-apa.

Detail fungsi hashing yang tersedia ada di dokumentasi resmi pgcrypto PostgreSQL.

Simpan garamnya di pengaturan server atau brankas rahasia, jangan di dalam query yang di-commit ke repositori.

Kapan pakai masking, bukan hashing?

Masking dipakai kalau orang yang lihat data masih butuh mengenali barisnya secara kasar, misalnya tim layanan pelanggan yang mau konfirmasi nomor ke penelepon.

SELECT
  repeat('*', length(no_hp) - 4) || right(no_hp, 4) AS no_hp_masked,
  left(nama, 1) || repeat('*', length(nama) - 1) AS nama_masked
FROM pelanggan;

Hasilnya **********1234 dan B*********.

Buat email, sisakan domainnya biar masih bisa dianalisa per penyedia:

SELECT
  left(email, 2) || '***@' || split_part(email, '@', 2) AS email_masked
FROM pelanggan;

Ingat, masking bukan pengaman kuat. Empat digit terakhir plus kota sering cukup buat orang yang udah kenal target. Pakai masking buat kenyamanan operasional, bukan buat dataset yang keluar dari perusahaan.

Gimana cara generalisasi kuasi-identitas?

Turunkan ketelitiannya. Umur jadi rentang, tanggal jadi bulan, kelurahan jadi kecamatan.

SELECT
  CASE
    WHEN umur < 25 THEN '18-24'
    WHEN umur < 35 THEN '25-34'
    WHEN umur < 45 THEN '35-44'
    ELSE '45+'
  END AS kelompok_umur,
  date_trunc('month', tanggal_daftar) AS bulan_daftar,
  kecamatan
FROM pelanggan;

Cara kerja date_trunc ada di tutorial DATE_TRUNC.

Buat nilai transaksi, potong ke kelipatan biar nggak jadi sidik jari:

SELECT floor(total_belanja / 100000) * 100000 AS belanja_dibulatkan
FROM transaksi;

Kenapa ini penting? Karena angka belanja 4.783.219 rupiah itu unik. Kalau lawan tau seorang pelanggan belanja segitu, dia langsung nemu barisnya walau semua kolom identitas udah dihapus.

Gimana cara ngecek datanya beneran aman?

Hitung berapa orang yang berbagi kombinasi kuasi-identitas yang sama. Kalau ada kombinasi yang cuma dimiliki 1 orang, dia bisa dikenali.

SELECT
  kelompok_umur,
  jenis_kelamin,
  kecamatan,
  COUNT(*) AS jumlah
FROM pelanggan_anonim
GROUP BY 1, 2, 3
HAVING COUNT(*) < 5
ORDER BY jumlah;

Query ini ngasih daftar kombinasi berisiko. Kalau hasilnya kosong, artinya tiap kombinasi minimal dimiliki 5 orang.

Angka 5 itu ambang yang lazim dipakai, bukan angka sakti. Kamu bisa naikin ke 10 atau 20 kalau datanya sensitif.

Buat kombinasi yang gagal, ada tiga pilihan: generalisasi lebih kasar lagi, buang barisnya, atau gabung kategori kecil jadi "lainnya".

DELETE FROM pelanggan_anonim
WHERE (kelompok_umur, jenis_kelamin, kecamatan) IN (
  SELECT kelompok_umur, jenis_kelamin, kecamatan
  FROM pelanggan_anonim
  GROUP BY 1, 2, 3
  HAVING COUNT(*) < 5
);

Contoh kasus: dataset pelanggan toko_berkah

Dataset latihan toko_berkah di ngulikdata punya tabel pelanggan dengan 1.204 baris. Kolomnya: nama, no_hp, tanggal_lahir, kelurahan, jenis_kelamin, dan total belanja 6 bulan.

Percobaan pertama: hapus nama dan nomor HP saja. Lalu jalankan query pengecekan pakai tanggal lahir persis, jenis kelamin, dan kelurahan.

Hasilnya bikin kaget. Dari 1.204 baris, 1.129 baris (93,8 persen) punya kombinasi yang unik. Artinya hampir semua pelanggan masih bisa dikenali oleh siapa pun yang tau tanggal lahir dan alamat mereka.

Percobaan kedua: tanggal lahir digeneralisasi jadi kelompok umur 10 tahunan, kelurahan dinaikkan jadi kecamatan.

Baris unik turun jadi 41 baris (3,4 persen). Jauh lebih baik, tapi masih ada.

Percobaan ketiga: 41 baris itu dibuang, dan kolom total belanja dibulatkan ke kelipatan 100 ribu.

Sisa 1.163 baris, nol kombinasi dengan jumlah di bawah 5. Kehilangan data 3,4 persen, dan semua analisa agregat per kecamatan masih jalan normal.

Yang aku catat dari sini: langkah generalisasi yang ngasih dampak paling besar itu naikin kelurahan jadi kecamatan. Sendirian, langkah itu motong baris unik dari 93,8 persen ke 12,1 persen.

Kolom lokasi yang terlalu detail hampir selalu jadi kebocoran terbesar. Cek itu duluan.

Kesalahan umum waktu anonimisasi data

Hashing tanpa garam. Udah dibahas di atas, tapi ini masih yang paling sering. Nomor HP, NIK, dan email semuanya punya ruang kemungkinan yang kecil.

Nyimpen garam di kolom tabel yang sama. Kalau file datanya bocor, garamnya ikut bocor. Simpan di tempat lain.

Lupa kolom teks bebas. Kolom catatan atau keluhan sering isinya "Bu Sari di Jalan Melati minta retur". Semua kerja anonimisasi kamu jadi sia-sia. Scan kolom teks pakai pola pencarian sebelum rilis.

Anonimisasi tapi tabel aslinya masih bisa diakses. Kalau siapa pun bisa JOIN tabel anonim ke tabel asli lewat urutan baris atau kolom ID, nggak ada gunanya. Bikin tabel anonim di skema terpisah dengan hak akses berbeda.

Ngerilis data agregat yang selnya terlalu kecil. Tabel "jumlah pelanggan per kecamatan per kelompok penghasilan" dengan sel berisi angka 1 itu sama saja membocorkan individu. Terapkan ambang minimum di hasil agregat juga.

Nyalin data produksi ke lingkungan uji tanpa dibersihkan. Basis data uji coba biasanya pengamanannya longgar. Ini pintu bocor yang paling sering kebuka.

Nggak nyatet apa yang udah dilakukan. Enam bulan lagi kamu nggak inget kolom mana yang di-hash dengan garam versi berapa. Tulis catatannya bareng querynya, dan perlakukan sebagai bagian dari ETL kamu.

Apa kata aturan di Indonesia?

Indonesia punya UU Nomor 27 Tahun 2022 tentang Pelindungan Data Pribadi. Intinya, pihak yang ngumpulin dan ngolah data pribadi punya kewajiban jaga data itu, dan pemilik data punya hak atas datanya.

Aku bukan ahli hukum, jadi aku nggak akan nafsirin pasalnya di sini. Yang jelas dari sisi teknis: makin sedikit data pribadi yang kamu simpan dan sebar, makin kecil risikonya.

Kalau proyek kamu menyangkut data pelanggan dalam jumlah besar, ajak tim legal atau konsultan yang paham aturannya sebelum rilis dataset ke pihak luar.

FAQ

Apa bedanya anonimisasi dan pseudonimisasi?

Pseudonimisasi ngganti identitas asli dengan kode, tapi kaitannya masih bisa dibalik kalau kamu punya kunci atau tabel pemetaan. Anonimisasi menghapus kemungkinan itu, jadi nggak ada cara balik ke individu aslinya. Praktisnya, data yang di-hash pakai garam rahasia itu pseudonim, bukan anonim, karena pemilik garam masih bisa mencocokkan.

Cukup nggak kalau aku hapus kolom nama dan nomor HP?

Nggak cukup. Kombinasi tanggal lahir, jenis kelamin, dan kode pos sering cukup buat nunjuk ke satu orang. Ini yang disebut kuasi-identitas. Setelah hapus identitas langsung, kamu masih perlu generalisasi kolom-kolom itu, lalu cek apakah ada kombinasi yang cuma dimiliki satu atau dua baris.

Aman nggak hashing nomor HP pakai MD5 atau SHA-256 polos?

Nggak aman buat data yang ruangnya kecil. Nomor HP Indonesia jumlah kemungkinannya terbatas, jadi siapa pun bisa hitung hash semua nomor dan cocokkan satu per satu. Itu namanya serangan kamus. Kamu wajib nambahin garam rahasia yang disimpan terpisah dari data, dan garam itu jangan pernah ikut ke file yang dibagikan.

Gimana cara tetap bisa gabung tabel setelah data di-hash?

Pakai garam yang sama untuk semua tabel di dalam satu lingkup analisa. Hash dari nomor HP yang sama bakal ngasih nilai yang sama, jadi JOIN tetap jalan. Yang perlu kamu jaga: jangan pakai garam yang sama buat dua penerima data berbeda, biar mereka nggak bisa gabungin data mereka jadi satu.

Perlu nggak anonimisasi buat data internal perusahaan?

Perlu buat lingkungan pengembangan dan pengujian. Basis data uji coba sering punya pengaman yang jauh lebih longgar dari produksi, dan di situ kebocoran paling sering terjadi. Salin data produksi ke lingkungan uji lewat proses yang otomatis nge-mask kolom sensitif, jangan salin mentah lalu janji bakal dibersihin nanti.

Penutup

Dua hal yang paling nentuin: kolom lokasi yang terlalu detail biasanya jadi kebocoran terbesar, dan hasil anonimisasi harus diuji pakai query, bukan diyakini.

Coba jalankan query pengecekan kombinasi di atas ke tabel pelanggan yang kamu pegang sekarang. Ganti kolomnya sesuai data kamu, lalu lihat berapa baris yang muncul.

Kalau angkanya besar, mulai dari generalisasi kolom lokasi dulu. Biasanya satu langkah itu udah motong sebagian besar risikonya.

Buat langkah pemeriksaan data lain sebelum rilis, ada daftarnya di query cek kualitas data.

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