Hasil query sering memuat baris yang kembar: daftar kota seluruh pelanggan menampilkan Bandung tiga kali, daftar tanggal transaksi menampilkan tanggal yang sama berulang. Query seperti “kota mana saja yang sudah punya pelanggan?” atau “tanggal berapa saja terjadi transaksi?” hanya butuh satu kemunculan per nilai. Kata kunci DISTINCT memerintahkan MySQL membandingkan seluruh baris hasil dan membuang baris yang identik dengan baris sebelumnya. Pada chapter ini — penutup Section Filtering dan Sorting — kita akan memakai DISTINCT pada satu kolom, membuktikan bahwa keunikannya berlaku pada kombinasi seluruh kolom, melihat perlakuan khusus terhadap NULL, lalu menutup dengan penghitungan nilai unik memakai COUNT(DISTINCT).
Menyiapkan Tabel Latihan #
Kita pakai tabel pelanggan dan pesanan dengan pola data yang sama seperti chapter-chapter sebelumnya. Kolom telepon sengaja memuat NULL pada sebagian baris, dan tabel pesanan memuat transaksi Budi Santoso yang tercatat dua kali pada tanggal yang sama — bahan alami untuk melihat duplikasi:
DROP DATABASE IF EXISTS belajar_filter;
CREATE DATABASE belajar_filter;
USE belajar_filter;Output yang Dihasilkan:
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Database changedCREATE TABLE pelanggan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
kota VARCHAR(50) NOT NULL,
telepon VARCHAR(20) NULL
);
INSERT INTO pelanggan (nama, kota, telepon) VALUES
('Budi Santoso', 'Bandung', '0812-5000-1001'),
('Siti Rahayu', 'Jakarta', '0813-5000-1002'),
('Andi Wijaya', 'Surabaya', NULL),
('Dewi Lestari', 'Bandung', '0815-5000-1004'),
('Rian Hidayat', 'Yogyakarta', NULL),
('Maya Putri', 'Medan', '0817-5000-1006'),
('Eko Prasetyo', 'Semarang', NULL),
('Fitri Handayani', 'Bandung', '0819-5000-1008');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0CREATE TABLE pesanan (
id INT AUTO_INCREMENT PRIMARY KEY,
nama_pelanggan VARCHAR(100) NOT NULL,
nama_produk VARCHAR(100) NOT NULL,
jumlah INT NOT NULL,
total DECIMAL(10,2) NOT NULL,
tanggal DATE NOT NULL
);
INSERT INTO pesanan (nama_pelanggan, nama_produk, jumlah, total, tanggal) VALUES
('Budi Santoso', 'Pensil 2B', 10, 30000.00, '2026-01-05'),
('Siti Rahayu', 'Kertas HVS A4', 2, 55000.00, '2026-01-18'),
('Dewi Lestari', 'Spidol Permanen', 3, 30000.00, '2026-02-01'),
('Budi Santoso', 'Kertas Origami', 5, 60000.00, '2026-02-14'),
('Maya Putri', 'Buku Tulis Sidu 38', 20, 90000.00, '2026-02-28'),
('Eko Prasetyo', 'Pulpen Gel Hitam', 4, 20000.00, '2026-03-05'),
('Fitri Handayani', 'Selotip Bening', 6, 48000.00, '2026-03-12'),
('Budi Santoso', 'Penghapus Putih', 12, 30000.00, '2026-03-25'),
('Budi Santoso', 'Pulpen Gel Hitam', 2, 10000.00, '2026-03-25');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 9 rows affected (0.00 sec)
Records: 9 Duplicates: 0 Warnings: 0DISTINCT pada Satu Kolom #
Sebagai titik banding, kita lihat dulu daftar kota tanpa DISTINCT:
SELECT kota
FROM pelanggan
ORDER BY kota;Output yang Dihasilkan:
+------------+
| kota |
+------------+
| Bandung |
| Bandung |
| Bandung |
| Jakarta |
| Medan |
| Semarang |
| Surabaya |
| Yogyakarta |
+------------+
8 rows in set (0.00 sec)Delapan baris tampil dan Bandung muncul tiga kali — sekali untuk Budi, Dewi, dan Fitri. Menambahkan DISTINCT tepat setelah kata kunci SELECT membuang baris kembar dari hasil:
SELECT DISTINCT kota
FROM pelanggan
ORDER BY kota;Output yang Dihasilkan:
+------------+
| kota |
+------------+
| Bandung |
| Jakarta |
| Medan |
| Semarang |
| Surabaya |
| Yogyakarta |
+------------+
6 rows in set (0.00 sec)Enam baris tersisa: Bandung, Jakarta, Medan, Semarang, Surabaya, dan Yogyakarta — masing-masing satu kemunculan. Bandung kini mewakili seluruh pelanggannya tanpa memedulikan jumlah pelanggan per kota. DISTINCT bekerja pada hasil query; data di tabel tetap utuh dan jumlah baris tabel tidak pernah berkurang.
DISTINCT pada Beberapa Kolom: Keunikan Kombinasi #
DISTINCT dengan beberapa kolom tidak membuat tiap kolom unik sendiri-sendiri; yang dibandingkan adalah kombinasi nilai seluruh kolom tersebut. Kita buktikan pada tabel pesanan, yang memuat dua transaksi Budi Santoso pada tanggal 2026-03-25. Pertama, satu kolom:
SELECT DISTINCT nama_pelanggan
FROM pesanan
ORDER BY nama_pelanggan;Output yang Dihasilkan:
+-----------------+
| nama_pelanggan |
+-----------------+
| Budi Santoso |
| Dewi Lestari |
| Eko Prasetyo |
| Fitri Handayani |
| Maya Putri |
| Siti Rahayu |
+-----------------+
6 rows in set (0.00 sec)Enam nama pelanggan unik tampil dari sembilan transaksi. Sekarang kita tambahkan kolom tanggal ke daftar SELECT:
SELECT DISTINCT nama_pelanggan, tanggal
FROM pesanan
ORDER BY nama_pelanggan, tanggal;Output yang Dihasilkan:
+-----------------+------------+
| nama_pelanggan | tanggal |
+-----------------+------------+
| Budi Santoso | 2026-01-05 |
| Budi Santoso | 2026-02-14 |
| Budi Santoso | 2026-03-25 |
| Dewi Lestari | 2026-02-01 |
| Eko Prasetyo | 2026-03-05 |
| Fitri Handayani | 2026-03-12 |
| Maya Putri | 2026-02-28 |
| Siti Rahayu | 2026-01-18 |
+-----------------+------------+
8 rows in set (0.00 sec)Hasilnya delapan baris, bukan enam. Budi Santoso kini tampil tiga kali — kombinasi dengan 2026-01-05, dengan 2026-02-14, dan dengan 2026-03-25 — karena tiap kombinasi nama dan tanggal dianggap nilai hasil yang berbeda. Dari sembilan transaksi, hanya satu kombinasi yang benar-benar kembar — dua transaksi Budi di tanggal 2026-03-25 — sehingga 9 baris menyusut menjadi 8. Inilah makna keunikan kombinasi: baris hanya dibuang bila seluruh kolom yang dipilih bernilai sama persis.
DISTINCT Bekerja pada Seluruh Baris Hasil #
Gotcha paling umum pemula: menaruh DISTINCT di depan daftar SELECT dan berharap hanya kolom pertama yang disaring unik. Kenyataannya DISTINCT membandingkan seluruh baris hasil, bukan kolom pertamanya. Kita buktikan dengan menambahkan kolom nama yang memang unik untuk setiap pelanggan:
SELECT DISTINCT kota, nama
FROM pelanggan
ORDER BY kota, nama;Output yang Dihasilkan:
+------------+-----------------+
| kota | nama |
+------------+-----------------+
| Bandung | Budi Santoso |
| Bandung | Dewi Lestari |
| Bandung | Fitri Handayani |
| Jakarta | Siti Rahayu |
| Medan | Maya Putri |
| Semarang | Eko Prasetyo |
| Surabaya | Andi Wijaya |
| Yogyakarta | Rian Hidayat |
+------------+-----------------+
8 rows in set (0.00 sec)Hasilnya delapan baris — sama persis dengan query tanpa DISTINCT. Kolom kota memang berulang (Bandung tiga kali), tetapi tidak ada dua baris yang kembar secara keseluruhan karena nama selalu berbeda, sehingga tidak ada satu baris pun yang dibuang. DISTINCT tidak gagal; DISTINCT hanya tidak melakukan apa yang kita kira. Kalau kebutuhannya memang “satu baris per kota”, satu kolom kota saja yang harus dipilih — atau gunakan GROUP BY bila perlu kolom tambahan hasil ringkasan.
DISTINCT dan NULL #
Perilaku menarik berikutnya menyangkut NULL. Kolom telepon memuat tiga baris NULL pada tabel pelanggan. Apa yang terjadi ketika kolom tersebut dijadikan satu-satunya kolom DISTINCT?
SELECT DISTINCT telepon
FROM pelanggan
ORDER BY telepon;Output yang Dihasilkan:
+----------------+
| telepon |
+----------------+
| NULL |
| 0812-5000-1001 |
| 0813-5000-1002 |
| 0815-5000-1004 |
| 0817-5000-1006 |
| 0819-5000-1008 |
+----------------+
6 rows in set (0.00 sec)Hasilnya enam baris: NULL tampil tepat satu kali diikuti lima nomor telepon. Tiga baris NULL dari Andi, Rian, dan Eko dilebur menjadi satu — untuk keperluan DISTINCT, seluruh NULL dianggap nilai yang sama, bukan “tidak bisa dibandingkan” seperti perilaku NULL = NULL pada chapter sebelumnya. Perbandingan baris kembar memakai kesamaan khusus yang memperlakukan NULL sama dengan NULL, sehingga duplikasi NULL pun tersaring. Posisi NULL di awal hasil sekadar mengikuti aturan ORDER BY dari chapter ORDER BY: baris NULL menempati posisi paling awal pada urutan menaik.
COUNT(DISTINCT): Menghitung Nilai Unik #
Kebutuhan “berapa banyak nilai berbeda” tidak mengharuskan kita menampilkan daftarnya. Fungsi agregat COUNT menerima bentuk COUNT(DISTINCT kolom) yang langsung menghitung jumlah nilai unik — dan, sejalan dengan perilaku agregat pada chapter sebelumnya, mengabaikan NULL sepenuhnya:
SELECT COUNT(DISTINCT kota) AS jumlah_kota,
COUNT(DISTINCT telepon) AS jumlah_telepon
FROM pelanggan;Output yang Dihasilkan:
+-------------+----------------+
| jumlah_kota | jumlah_telepon |
+-------------+----------------+
| 6 | 5 |
+-------------+----------------+
1 row in set (0.00 sec)Ada 6 kota berbeda dan 5 nomor telepon berbeda. Perbedaan angka ini bukan kebetulan: COUNT(DISTINCT telepon) menghitung nilai unik yang tidak NULL saja, sehingga satu nilai NULL kolektif ikut diabaikan — berbeda dengan SELECT DISTINCT telepon di atas yang masih menampilkan NULL sebagai satu baris. Jadi pertanyaan “ada berapa nilai unik termasuk NULL” dan “ada berapa nilai unik tanpa NULL” bisa menghasilkan dua jawaban berbeda, dan bentuk COUNT(DISTINCT) menjawab yang kedua.
Kombinasi multi kolom juga didukung — cukup beri koma di dalam kurung. Query berikut menghitung berapa kombinasi unik pelanggan dan tanggal transaksi:
SELECT COUNT(DISTINCT nama_pelanggan, tanggal) AS kombinasi_unik
FROM pesanan;Output yang Dihasilkan:
+----------------+
| kombinasi_unik |
+----------------+
| 8 |
+----------------+
1 row in set (0.00 sec)Hasilnya 8 — angka yang sama dengan daftar SELECT DISTINCT nama_pelanggan, tanggal di awal chapter, karena keduanya memakai definisi keunikan yang sama persis.
Membersihkan Database Latihan #
Latihan terakhir section ini selesai. Kita jatuhkan database latihan bersama kedua tabelnya:
DROP DATABASE belajar_filter;Output yang Dihasilkan:
Query OK, 2 rows affected (0.00 sec)Referensi #
- SELECT Statement — MySQL 8.4 Reference Manual
- DISTINCT Optimization — MySQL 8.4 Reference Manual
- Aggregate Functions — MySQL 8.4 Reference Manual
Section Filtering dan Sorting kini tuntas: kita bisa menyaring baris dengan WHERE dan segenap operatornya, menangani NULL, mengurutkan dengan ORDER BY, memotong hasil dengan LIMIT dan OFFSET, serta menyetrip baris kembar dengan DISTINCT. Kumpulan kemampuan ini sudah menempuh separuh perjalanan DQL — selanjutnya kita beranjak dari membaca baris ke meringkasnya: fungsi-fungsi agregat seperti SUM, AVG, dan COUNT akan menjadi pintu masuk Section Agregasi.