Đôi khi database giống như một người hay quên — ghi lại hết mọi thứ, nhưng lại quên là đã ghi rồi. Kết quả là bạn mở bảng thành phố của khách hàng ra, thấy mười cái "Berlin", năm cái "Seattle" và một đống bản ghi lặp lại. Chuyện này xảy ra khi cùng một thành phố xuất hiện ở nhiều khách hàng khác nhau. Nhưng bạn đâu muốn chạy chiến dịch quảng cáo cho mười cái "Berlin" khi thực ra chỉ có một thành phố thôi đúng không?
Để lấy ra giá trị duy nhất — không có trùng lặp — có một lệnh cực tiện là DISTINCT. Nó giống như cây chổi thần kỳ: quét một phát là hết dòng trùng, chỉ còn lại những gì thực sự khác biệt thôi.
DISTINCT cho phép lấy ra chỉ những dòng duy nhất từ kết quả truy vấn. Cực kỳ hữu ích khi bạn cần loại bỏ dữ liệu trùng, ví dụ như:
- Sản phẩm duy nhất trong đơn hàng.
- Tên khách hàng duy nhất.
- Kết hợp dữ liệu duy nhất, ví dụ "thành phố + quốc gia".
DISTINCT hoạt động như thế nào?
Cú pháp DISTINCT đơn giản và dễ hiểu, đúng kiểu SQL luôn:
SELECT DISTINCT cột1, cột2, ...
FROM bảng;
Khi bạn thêm DISTINCT vào truy vấn, database đảm bảo mỗi dòng trong kết quả là duy nhất.
Ví dụ dùng DISTINCT
Bắt đầu với mấy ví dụ kinh điển để hiểu cách DISTINCT chạy nhé.
Ví dụ 1: Giá trị duy nhất của một cột
Giả sử có bảng students chứa dữ liệu sinh viên:
-- Bảng students
| id | first_name | last_name | city |
|---|---|---|---|
| 1 | Maria | Chi | Seattle |
| 2 | Alex | Lin | Toronto |
| 3 | Anna | Song | Seattle |
| 4 | Nat | Cole | Chicago |
| 5 | Maria | Chi | Seattle |
Mình muốn biết sinh viên đến từ những thành phố nào. Viết truy vấn
SELECT city
FROM students;
và nhận được kết quả:
| city |
|---|
| Seattle |
| Toronto |
| Seattle |
| Chicago |
| Seattle |
Không đúng ý mình lắm :(
Để loại trùng thì dùng DISTINCT thôi:
SELECT DISTINCT city
FROM students;
Kết quả:
| city |
|---|
| Seattle |
| Toronto |
| Chicago |
Không có DISTINCT thì "Seattle" xuất hiện ba lần, trong khi mình chỉ cần mỗi thành phố một lần thôi.
Ví dụ 2: Giá trị duy nhất của nhiều cột
Giờ thử lấy ra kết hợp duy nhất "tên + họ", vì có thể sinh viên trùng tên hoặc trùng họ.
Vẫn là bảng students nhé:
-- Bảng students
| id | first_name | last_name | city |
|---|---|---|---|
| 1 | Maria | Chi | Seattle |
| 2 | Alex | Lin | Toronto |
| 3 | Anna | Song | Seattle |
| 4 | Nat | Cole | Chicago |
| 5 | Maria | Chi | Seattle |
Truy vấn:
SELECT DISTINCT first_name, last_name
FROM students;
Kết quả:
| first_name | last_name |
|---|---|
| Maria | Chi |
| Alex | Lin |
| Anna | Song |
| Nat | Cole |
Vậy là DISTINCT hoạt động như bộ lọc: nó xét tất cả các cột được chỉ định và loại trùng chỉ những dòng mà giá trị của tất cả các cột đó giống nhau.
Ví dụ 3: Kết hợp duy nhất và sắp xếp
Giờ kết hợp DISTINCT với ORDER BY để lấy giá trị duy nhất, sắp xếp theo họ theo thứ tự alphabet.
Vẫn là bảng students:
-- Bảng students
| id | first_name | last_name | city |
|---|---|---|---|
| 1 | Maria | Chi | Seattle |
| 2 | Alex | Lin | Toronto |
| 3 | Anna | Song | Seattle |
| 4 | Nat | Cole | Chicago |
| 5 | Maria | Chi | Seattle |
Truy vấn:
SELECT DISTINCT first_name, last_name
FROM students
ORDER BY last_name ASC;
Kết quả:
| first_name | last_name |
|---|---|
| Maria | Chi |
| Nat | Cole |
| Alex | Lin |
| Anna | Song |
Dòng trùng đã bị loại, họ được sắp xếp theo alphabet.
Ví dụ 4: Dùng với hàm tổng hợp
Nếu thử dùng DISTINCT với hàm, ví dụ COUNT thì sao?
SELECT COUNT(DISTINCT city) AS unique_city_count
FROM students;
Kết quả:
| unique_city_count |
|---|
| 3 |
Truy vấn này trả về số lượng thành phố duy nhất. Quá tiện đúng không?
Lưu ý khi dùng DISTINCT
Khi dùng DISTINCT cần nhớ là nó xét tất cả các cột được chỉ định. Nếu bạn thêm nhiều cột vào truy vấn, kết quả có thể thay đổi.
Ví dụ 5: Tại sao phải hiểu rõ ngữ cảnh?
Nếu bạn thêm cột vào truy vấn, nó sẽ ảnh hưởng đến tính duy nhất của dòng.
SELECT DISTINCT first_name, city
FROM students;
Bảng students:
| id | first_name | last_name | city |
|---|---|---|---|
| 1 | Maria | Chi | Seattle |
| 2 | Alex | Lin | Austin |
| 3 | Anna | Song | Seattle |
| 4 | Otto | Art | Denver |
| 5 | Maria | Chi | Portland |
Kết quả:
| first_name | city |
|---|---|
| Maria | Seattle |
| Alex | Austin |
| Anna | Seattle |
| Otto | Denver |
| Maria | Portland |
Mỗi kết hợp "tên + thành phố" giờ là duy nhất. Nhớ nhé: tính duy nhất được xác định bởi tất cả các cột chỉ định, không phải từng cột riêng lẻ.
Lỗi thường gặp khi dùng DISTINCT
Một trong những lỗi phổ biến nhất khi dùng DISTINCT là hiểu nhầm truy vấn thực sự làm gì. Ví dụ, nếu bạn chỉ định quá nhiều cột, kết quả có thể khác xa mong đợi vì tính duy nhất sẽ dựa trên tất cả các cột.
Ví dụ:
SELECT DISTINCT *
FROM students;
Lúc này mỗi dòng đều được coi là duy nhất, vì tất cả các cột đều được xét.
Một lỗi nữa — dùng DISTINCT khi không cần thiết. Nếu bạn chắc chắn dữ liệu đã duy nhất (ví dụ cột là primary key), thì DISTINCT chỉ làm database tốn công vô ích thôi.
GO TO FULL VERSION