DHDataHọc
Lý thuyếtBài 9/305 phút đọc+10 XP

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 LIKE vớ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ả LIKE khác dự đoán.
  • Dùng ILIKE khi cần so khớp không phân biệt hoa/thường.
  • Nhận ra vì sao NULL khô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:

code
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ó:

code
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ĩaVí 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:

  1. Phân biệt hoa/thường. LIKE 'hà%' không khớp 'Hà Nội' vì H khác h. Dùng ILIKE để bỏ qua khác biệt này.
  2. 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 extension unaccent.
  3. NULL không tham gia. Một dòng có cột NULL không bao giờ khớp LIKE, 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àmViệc làmVí dụ
LOWER(s)Chuyển thành chữ thườngLOWER(city) = 'hà nội'
UPPER(s)Chuyển thành chữ hoaUPPER(name) LIKE 'AN%'
TRIM(s)Bỏ khoảng trắng hai đầuTRIM(city) = 'Hà Nội'
LENGTH(s)Độ dài chuỗiLENGTH(name) > 10

Ví dụ chạy được

Tìm khách ở các thành phố bắt đầu bằng Hà:

code
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:

code
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:

code
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ọ:

code
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ự:

code
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:

code
SELECT name FROM customers WHERE city LIKE 'hà%';   -- 0 dòng
SELECT name FROM customers WHERE city ILIKE 'hà%';  -- 3 dòng

Kế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

  1. Đế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ẫu LIKE.
  2. Tìm các khách có tên chứa 'inh' bằng name 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ình chứa ình, không phải inh; hãy chạy để xác nhận và giải thích.
  3. Viết truy vấn tìm email kết thúc bằng '@example.com' rồi đổi thành NOT LIKE. So sánh tổng hai kết quả với 12 và giải thích phần chênh lệch.
  4. 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ằng H.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
column "Hà Nội" does not existDùng nháy kép cho chuỗiDùng nháy đơn 'Hà Nội'
LIKE 'Ha%' trả 0 dòngDữ liệu có dấu, mẫu không dấuDùng đúng dấu hoặc chuẩn hóa bằng unaccent
LIKE 'hà%' trả 0 dòngKhác hoa/thườngDùng ILIKE hoặc LOWER
Khách chưa có email không xuất hiệnNULL không khớp LIKELọc riêng bằng IS NULL
Mẫu chứa % hoặc _ khớp quá nhiềuKý tự đại diện chưa được thoátDù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ự.
  • LIKE phân biệt hoa/thường và dấu tiếng Việt; ILIKE bỏ qua hoa/thường.
  • NULL không khớp bất kỳ mẫu nào, kể cả '%'; dùng IS 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