Foto oleh panumas nikhomkhai via Pexels

Data duplikat sering muncul ketika menggabungkan beberapa table atau ketika sebuah table memang menyimpan baris yang mirip satu sama lain. Duplikasi ini bisa membuat laporan menampilkan angka yang salah, misalnya jumlah pelanggan unik yang sebenarnya lebih sedikit dari yang terlihat karena satu pelanggan muncul berkali-kali akibat relasi dengan table order.

SQL Server menyediakan klausa DISTINCT untuk menghilangkan baris duplikat dari hasil query. Artikel ini membahas cara kerja DISTINCT, perbedaannya saat diterapkan pada satu atau banyak kolom, dan kapan sebaiknya DISTINCT dihindari karena menutupi masalah struktural yang lebih dalam.

Cara Kerja DISTINCT

DISTINCT menghapus baris yang identik

-- Tanpa DISTINCT: kota yang sama bisa muncul berkali-kali SELECT City FROM Customers; -- Dengan DISTINCT: setiap kota hanya muncul sekali SELECT DISTINCT City FROM Customers; -- Expected: jika ada 500 customer namun hanya 12 kota berbeda, -- hasil DISTINCT akan menampilkan tepat 12 baris

DISTINCT bekerja dengan membandingkan seluruh kolom yang dipilih pada setiap baris, lalu hanya menyisakan satu baris untuk setiap kombinasi nilai yang unik. Proses ini membutuhkan SQL Server untuk mengurutkan atau melakukan hashing data secara internal sebelum bisa menentukan baris mana yang duplikat.

DISTINCT pada Lebih dari Satu Kolom

Kombinasi unik dari dua kolom sekaligus

SELECT DISTINCT City, Province FROM Customers; -- Expected: baris dengan City='Jakarta', Province='DKI Jakarta' -- dan City='Jakarta', Province='Jawa Barat' (contoh kasus beda data) -- dianggap BERBEDA, keduanya muncul di hasil

Saat DISTINCT diterapkan pada lebih dari satu kolom, SQL Server menganggap satu baris duplikat hanya jika seluruh kombinasi kolom sama persis, bukan masing-masing kolom secara terpisah. Ini sering membingungkan pemula yang mengira DISTINCT bekerja per kolom secara independen.

Dampak DISTINCT terhadap Performa

DISTINCT memerlukan proses pengurutan atau hashing internal untuk mendeteksi duplikat, sehingga pada table besar bisa lebih lambat dibanding query tanpa DISTINCT. Sebelum menambahkan DISTINCT, ada baiknya memeriksa apakah duplikat sebenarnya berasal dari JOIN yang salah.

DISTINCT sering dipakai untuk menutupi JOIN yang menghasilkan duplikasi

-- Duplikat muncul karena JOIN menghasilkan baris ganda SELECT c.FullName FROM Customers c JOIN Orders o ON o.CustomerId = c.CustomerId; -- Satu customer dengan 3 order akan muncul 3 kali -- DISTINCT 'menutupi' gejala, bukan memperbaiki akar masalah SELECT DISTINCT c.FullName FROM Customers c JOIN Orders o ON o.CustomerId = c.CustomerId;

Alternatif yang Lebih Tepat: Memperbaiki Query Asal

Jika tujuan sebenarnya adalah mendapatkan daftar pelanggan yang pernah order (tanpa peduli berapa kali), pendekatan yang lebih tepat dan lebih efisien adalah menggunakan EXISTS atau subquery, bukan JOIN yang menghasilkan duplikasi lalu di-DISTINCT belakangan.

EXISTS menghindari duplikasi tanpa perlu DISTINCT

SELECT FullName FROM Customers c WHERE EXISTS ( SELECT 1 FROM Orders o WHERE o.CustomerId = c.CustomerId ); -- Expected: hasil identik dengan versi DISTINCT di atas, -- namun SQL Server bisa berhenti begitu menemukan satu order yang cocok, -- tanpa perlu membaca dan menggabungkan semua order milik customer tersebut

DISTINCT pada Banyak Kolom dan Perbedaannya dengan GROUP BY

DISTINCT pada dua kolom sekaligus dibandingkan GROUP BY

-- DISTINCT berlaku untuk kombinasi SELURUH kolom yang disebut SELECT DISTINCT City, Province FROM Customers; -- Expected: kombinasi City+Province unik, -- bukan hanya City unik secara terpisah -- Pendekatan setara memakai GROUP BY SELECT City, Province FROM Customers GROUP BY City, Province;

Ketika DISTINCT diterapkan pada lebih dari satu kolom, SQL Server menganggap kombinasi seluruh kolom tersebut sebagai satu kesatuan yang harus unik, bukan menerapkan keunikan pada tiap kolom secara terpisah. Artinya baris dengan City yang sama namun Province berbeda tetap akan dianggap baris yang berbeda dan sama-sama muncul di hasil akhir, karena kombinasi keduanya tidak sama persis.

Secara fungsional, SELECT DISTINCT pada beberapa kolom menghasilkan output yang identik dengan menulis GROUP BY pada kolom-kolom yang sama tanpa fungsi agregat apa pun; keduanya sama-sama memberi tahu SQL Server untuk mengelompokkan baris dengan kombinasi nilai sama menjadi satu baris representatif. Perbedaannya lebih ke gaya penulisan dan maksud yang ingin disampaikan ke pembaca kode.

GROUP BY umumnya lebih dipilih ketika query juga perlu menghitung fungsi agregat seperti COUNT atau SUM per kelompok, sedangkan DISTINCT lebih cocok dipakai ketika tujuannya murni menghilangkan baris duplikat tanpa perhitungan tambahan; memilih yang sesuai tujuan membuat maksud query lebih mudah dipahami pembaca lain.

Menggunakan DISTINCT bersama ORDER BY pada Kolom yang Tidak Dipilih

Batasan ORDER BY saat dipakai bersama DISTINCT

-- DISTINCT dengan ORDER BY pada kolom yang ikut di-SELECT, ini valid SELECT DISTINCT Kota FROM dbo.Pelanggan ORDER BY Kota ASC; -- Ini akan GAGAL: mengurutkan berdasarkan kolom yang tidak termasuk -- dalam daftar SELECT DISTINCT -- SELECT DISTINCT Kota FROM dbo.Pelanggan -- ORDER BY TanggalDaftar DESC; -- Error: Msg 145, kolom ORDER BY harus muncul pada daftar SELECT -- jika SELECT mengandung DISTINCT -- Solusi: sertakan kolom yang dipakai untuk urutan ke dalam SELECT SELECT DISTINCT Kota, TanggalDaftar FROM dbo.Pelanggan ORDER BY TanggalDaftar DESC;

SQL Server menerapkan aturan ketat ketika DISTINCT dan ORDER BY dipakai bersamaan: setiap kolom yang disebut pada klausa ORDER BY wajib muncul pula pada daftar kolom di SELECT. Aturan ini berbeda dari query SELECT biasa tanpa DISTINCT, yang masih mengizinkan ORDER BY memakai kolom di luar daftar SELECT selama kolom tersebut tetap ada pada table sumber.

Alasan di balik batasan ini bersifat konseptual: DISTINCT bekerja dengan menggabungkan baris-baris yang nilainya identik pada kolom yang dipilih menjadi satu baris representatif, sehingga jika ORDER BY diizinkan memakai kolom lain yang tidak ikut dipilih dan tidak ikut dalam proses deduplikasi, hasilnya menjadi ambigu karena satu baris hasil DISTINCT bisa saja mewakili banyak baris asli dengan nilai kolom tersembunyi yang berbeda-beda.

Ketika kebutuhan bisnis memang mengharuskan pengurutan berdasarkan kolom yang tidak ingin ditampilkan, solusi yang umum dipakai adalah membungkus query dalam Common Table Expression atau subquery yang menyertakan kolom tambahan tersebut untuk keperluan pengurutan, lalu menampilkan hanya kolom yang relevan pada query terluar, atau beralih memakai GROUP BY yang memiliki fleksibilitas lebih dalam menggabungkannya dengan fungsi agregat atas kolom lain, sehingga kebutuhan pengurutan dan deduplikasi dapat dipisahkan secara lebih jelas.

Perlakuan NULL pada DISTINCT: Dianggap Satu Nilai yang Sama

DISTINCT menggabungkan seluruh NULL

-- Data: 5 baris, 3 di antaranya NoHP bernilai NULL SELECT DISTINCT NoHP FROM dbo.Pelanggan; -- Hasil: seluruh NULL digabung menjadi SATU baris NULL, -- bukan dianggap sebagai nilai-nilai berbeda -- NoHP -- 081234567890 -- 089988776655 -- NULL -- hanya muncul sekali meski aslinya ada 3 baris NULL

Meskipun secara logis NULL berarti nilai tidak diketahui dan dua NULL seharusnya tidak bisa dibandingkan sama satu sama lain, DISTINCT memperlakukan seluruh baris NULL pada kolom yang sama sebagai satu kelompok nilai yang setara untuk keperluan deduplikasi, sehingga seluruh baris dengan NoHP NULL hanya diwakili satu baris NULL pada hasil akhir, bukan tetap muncul berkali-kali.

Perilaku khusus ini berbeda dari operator perbandingan biasa seperti pada klausa WHERE, di mana NULL = NULL selalu menghasilkan UNKNOWN, bukan TRUE. DISTINCT, GROUP BY, dan beberapa operator himpunan seperti UNION memang sengaja diberi aturan khusus agar NULL bisa dikelompokkan secara konsisten, dan memahami perbedaan ini mencegah kebingungan saat jumlah baris unik yang dilaporkan tidak sesuai dugaan awal.

Kesalahan Umum yang Sering Terjadi

Menambahkan DISTINCT tanpa memeriksa penyebab duplikasi

DISTINCT yang ditambahkan secara reflek begitu melihat data duplikat sering kali hanya menutupi gejala dari JOIN atau subquery yang sebenarnya perlu diperbaiki strukturnya.

Mengira DISTINCT bekerja per kolom pada SELECT banyak kolom

DISTINCT pada beberapa kolom mengevaluasi kombinasi seluruh kolom tersebut, bukan menghapus duplikat masing-masing kolom secara terpisah — kesalahpahaman ini sering menghasilkan jumlah baris yang tidak sesuai ekspektasi.

Memakai DISTINCT pada tabel sangat besar tanpa mempertimbangkan biaya performa

Pada tabel dengan puluhan juta baris, operasi DISTINCT bisa memakan waktu signifikan karena butuh sorting/hashing internal, terutama jika tidak didukung indeks yang sesuai pada kolom yang di-DISTINCT.

Kapan Pendekatan Ini Tidak Cocok Dipakai

DISTINCT cocok dipakai untuk kebutuhan eksploratif cepat, misalnya mengecek 'ada kota apa saja di data pelanggan', namun untuk query produksi yang dijalankan berulang kali dengan frekuensi tinggi, lebih baik menelusuri akar penyebab duplikasi dan memperbaikinya di level JOIN atau struktur data.

Ringkasan

DISTINCT berguna untuk mengambil nilai unik dari sebuah kolom atau kombinasi kolom, namun sebaiknya dipakai setelah memastikan struktur query dan JOIN sudah benar, bukan sebagai solusi cepat menutupi query yang kurang tepat.

Kebiasaan menelusuri akar masalah duplikasi data, alih-alih langsung menambahkan DISTINCT, akan membuat query jauh lebih efisien dan mudah dipahami oleh developer lain yang membacanya di kemudian hari.

Seri Belajar SQL Server:

← Sebelumnya: Membatasi Hasil Query dengan TOP

→ Selanjutnya: Pencarian Pola dengan LIKE