Lọc theo chuỗi
Bạn sẽ học được
- Viết literal chuỗi đúng quy ước của SQL, kể cả khi chuỗi chứa dấu nháy.
- Dùng
LIKEvới%và_để lọc theo mẫu thay vì so khớp tuyệt đối. - Hiểu vì sao dấu tiếng Việt và hoa/thường làm kết quả
LIKEkhác dự đoán. - Dùng
ILIKEkhi cần so khớp không phân biệt hoa/thường. - Nhận ra vì sao
NULLkhông bao giờ xuất hiện trong kết quảLIKE.
Khái niệm cốt lõi
Chuỗi trong SQL đặt trong dấu nháy đơn:
SELECT name FROM customers WHERE city = 'Hà Nội';Dấu nháy kép có ý nghĩa khác: chúng đánh dấu tên cột hoặc tên bảng, không phải chuỗi. Viết WHERE city = "Hà Nội" sẽ khiến PostgreSQL đi tìm một cột tên là Hà Nội và báo lỗi. Đây là điểm khác biệt lớn so với JavaScript hay Python, nơi hai loại nháy thường dùng thay nhau.
Nếu chuỗi cần chứa dấu nháy đơn, nhân đôi nó:
SELECT 'O''Brien' AS ten;Kết quả là O'Brien. Cách này hơi lạ nhưng là chuẩn SQL, hoạt động ở mọi hệ quản trị cơ sở dữ liệu.
So khớp bằng = chỉ đúng khi chuỗi giống hệt từng ký tự. LIKE mở rộng thành so khớp theo mẫu, với hai ký tự đại diện:
| Ký tự | Ý nghĩa | Ví dụ | Khớp |
|---|---|---|---|
% | Không hoặc nhiều ký tự bất kỳ | 'Hà%' | Hà Nội, Hà Tĩnh |
_ | Đúng một ký tự bất kỳ | '_n%' | An Nguyễn, Inh Đỗ |
Mẫu không có % hoặc _ tương đương với =. Mẫu '%' khớp mọi chuỗi không NULL. Mẫu 'Hà%' khớp mọi chuỗi bắt đầu bằng Hà; '%Nội' khớp mọi chuỗi kết thúc bằng Nội; '%Hà%' khớp mọi chuỗi chứa Hà ở bất kỳ đâu.
Có ba điều khiến LIKE khó đoán hơn tưởng tượng:
- Phân biệt hoa/thường.
LIKE 'hà%'không khớp'Hà Nội'vìHkhách. DùngILIKEđể bỏ qua khác biệt này. - Phân biệt dấu tiếng Việt.
'Hà Nội'và'Ha Noi'là hai chuỗi khác nhau.LIKE 'Ha%'không khớp'Hà Nội'; muốn tìm không dấu phải chuẩn hóa dữ liệu trước, ví dụ bằng extensionunaccent. NULLkhông tham gia. Một dòng có cộtNULLkhông bao giờ khớpLIKE, kể cả mẫu'%'. Đây là hành vi đúng của SQL ba giá trị, không phải lỗi.
Với % và _ nằm trong dữ liệu thật (ví dụ tên sản phẩm có dấu phần trăm), cần thoát bằng ESCAPE. Dữ liệu của khóa học không có trường hợp này, nhưng biết để tránh bất ngờ khi làm việc với dữ liệu thật.
Một số hàm chuỗi hữu ích đi kèm:
| Hàm | Việc làm | Ví dụ |
|---|---|---|
LOWER(s) | Chuyển thành chữ thường | LOWER(city) = 'hà nội' |
UPPER(s) | Chuyển thành chữ hoa | UPPER(name) LIKE 'AN%' |
TRIM(s) | Bỏ khoảng trắng hai đầu | TRIM(city) = 'Hà Nội' |
LENGTH(s) | Độ dài chuỗi | LENGTH(name) > 10 |
Ví dụ chạy được
Tìm khách ở các thành phố bắt đầu bằng Hà:
SELECT name, city
FROM customers
WHERE city LIKE 'Hà%'
ORDER BY name;Ba dòng: An Nguyễn (Hà Nội), Dũng Phạm (Hà Nội), Khánh Hồ (Hà Nội). Hà Bùi ở Hải Phòng không xuất hiện — dù tên bắt đầu bằng Hà, cột city của cô là Hải Phòng, và Hải khác Hà ở dấu thanh. Đây là ví dụ rõ ràng cho việc phải lọc đúng cột.
Tìm khách có email:
SELECT name, email
FROM customers
WHERE email LIKE '%@example.com'
ORDER BY id;Mười dòng. Hai khách Dũng Phạm và Inh Đỗ có email là NULL, nên không xuất hiện — kể cả khi mẫu '%' cũng bỏ qua chúng. Nếu muốn đếm khách chưa có email, phải viết điều kiện ngược lại bằng IS NULL, không dùng NOT LIKE:
SELECT name
FROM customers
WHERE email IS NULL;Hai dòng: Dũng Phạm, Inh Đỗ. Còn email NOT LIKE '%@example.com' cũng chỉ trả về những dòng có email khác mẫu, không trả NULL.
Tìm theo họ:
SELECT name
FROM customers
WHERE name LIKE '%Nguyễn';Một dòng: An Nguyễn. Mẫu có % ở đầu nên không tận dụng được chỉ mục thông thường; với bảng nhỏ không sao, nhưng với bảng triệu dòng, tìm kiếm kiểu này chậm hơn nhiều so với tìm theo tiền tố.
Dùng _ để khớp đúng một ký tự:
SELECT name
FROM customers
WHERE name LIKE '_n%';Hai dòng: An Nguyễn và Inh Đỗ. Mẫu đọc là "một ký tự bất kỳ, rồi n, rồi phần còn lại". Tên An có A + n; Inh có I + n. Các tên khác như Bình có ký tự thứ hai là ì, không khớp.
Cuối cùng, so sánh LIKE và ILIKE khi chữ hoa/thường khác nhau:
SELECT name FROM customers WHERE city LIKE 'hà%'; -- 0 dòng
SELECT name FROM customers WHERE city ILIKE 'hà%'; -- 3 dòngKết quả thứ nhất rỗng vì dữ liệu lưu Hà Nội với H hoa. ILIKE là phần mở rộng của PostgreSQL (không có trong chuẩn SQL), rất tiện khi dữ liệu nhập tay không nhất quán.
Thực hành
- Đếm số khách theo từng thành phố bằng
WHERE city = '...'. Kết quả phải cộng lại bằng 12. Đây là bước đầu tiên trước khi tin vào một mẫuLIKE. - Tìm các khách có tên chứa
'inh'bằngname LIKE '%inh%'. Kết quả là Linh Ngô, Minh Dương và Inh Đỗ — ba dòng. Bình Trần không khớp vìBìnhchứaình, không phảiinh; hãy chạy để xác nhận và giải thích. - Viết truy vấn tìm email kết thúc bằng
'@example.com'rồi đổi thànhNOT LIKE. So sánh tổng hai kết quả với 12 và giải thích phần chênh lệch. - Thử
SELECT name FROM customers WHERE city LIKE 'H%';và cho biết vì sao kết quả chỉ có bốn dòng, dù có năm thành phố bắt đầu bằngH.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
column "Hà Nội" does not exist | Dùng nháy kép cho chuỗi | Dùng nháy đơn 'Hà Nội' |
LIKE 'Ha%' trả 0 dòng | Dữ liệu có dấu, mẫu không dấu | Dùng đúng dấu hoặc chuẩn hóa bằng unaccent |
LIKE 'hà%' trả 0 dòng | Khác hoa/thường | Dùng ILIKE hoặc LOWER |
| Khách chưa có email không xuất hiện | NULL không khớp LIKE | Lọc riêng bằng IS NULL |
Mẫu chứa % hoặc _ khớp quá nhiều | Ký tự đại diện chưa được thoát | Dùng ESCAPE với ký tự thoát tự chọn |
Lỗi thứ tư hay bị hiểu sai là "truy vấn sai". Thực ra nó đúng: NULL nghĩa là "không biết giá trị", nên không thể khẳng định nó khớp hay không khớp một mẫu. SQL trả về unknown, và WHERE chỉ giữ true. Hiểu điều này sẽ giúp bạn viết các truy vấn đếm chính xác hơn — đặc biệt khi kiểm tra dữ liệu thiếu.
Tóm tắt
- Chuỗi dùng nháy đơn; nháy kép là tên cột/bảng.
%khớp nhiều ký tự,_khớp đúng một ký tự.LIKEphân biệt hoa/thường và dấu tiếng Việt;ILIKEbỏ qua hoa/thường.NULLkhông khớp bất kỳ mẫu nào, kể cả'%'; dùngIS NULLđể tìm.- Kiểm tra mẫu bằng phép đếm và đối chiếu với tổng số dòng.
Dùng ← → để chuyển bài