Bài tập: lọc khách Hà Nội
Bạn sẽ học được
- Chuyển một yêu cầu tiếng Việt thành câu
WHEREhoàn chỉnh. - Áp checklist năm câu hỏi trước khi viết SQL.
- Đối chiếu kết quả với dữ liệu gốc thay vì tin vào cảm giác.
- Hiểu vì sao bài chấm dùng thêm bộ dữ liệu ẩn và cách viết truy vấn tổng quát.
- Đọc phản hồi chấm bài để sửa đúng chỗ.
Khái niệm cốt lõi
Đề bài Khách hàng ở Hà Nội:
Lấy
namecủa các khách hàng cócity = 'Hà Nội', sắp xếp theo tên.
Đây là bài luyện đầu tiên của chương, và cũng là dạng bài sẽ gặp nhiều nhất khi đi làm: một yêu cầu bằng ngôn ngữ tự nhiên, cần chuyển thành truy vấn chính xác. Dùng lại checklist năm câu hỏi từ chương 1:
| Câu hỏi | Trả lời | Thành phần SQL |
|---|---|---|
| Bảng nào? | customers | FROM customers |
| Cột nào? | Chỉ name | SELECT name |
| Lọc gì? | city = 'Hà Nội' | WHERE city = 'Hà Nội' |
| Thứ tự? | Theo tên | ORDER BY name |
| Giới hạn? | Không | không có LIMIT |
Ghép lại:
SELECT name
FROM customers
WHERE city = 'Hà Nội'
ORDER BY name;Kết quả trên bộ dữ liệu hiển thị có ba dòng:
| name |
|---|
| An Nguyễn |
| Dũng Phạm |
| Khánh Hồ |
Ba dòng này đúng, nhưng chưa đủ để kết luận truy vấn đúng. Bài chấm còn chạy trên một bộ dữ liệu ẩn có thêm khách Oanh Tạ ở Hà Nội. Truy vấn đúng phải trả bốn dòng trên bộ ẩn. Đây là lý do không được "chép kết quả": nếu bạn viết WHERE name IN ('An Nguyễn', 'Dũng Phạm', 'Khánh Hồ'), bài hiển thị sẽ đạt nhưng bài ẩn sẽ sai. Điều đang được kiểm tra là quy tắc lọc, không phải danh sách kết quả.
Vì sao phải có ORDER BY name? Vì đề nói "sắp xếp theo tên". Trên bảng nhỏ, PostgreSQL có thể tình cờ trả đúng thứ tự, nhưng không có gì bảo đảm. Bài chấm so sánh cả thứ tự dòng khi đề yêu cầu, nên thiếu ORDER BY là thiếu một phần đáp án.
Một điểm tinh tế: ORDER BY name sắp theo thứ tự của kiểu chữ, không theo tiếng Việt có dấu một cách "tự nhiên" như con người mong đợi. Với ba cái tên này, thứ tự A → D → K trùng với thứ tự alphabet thông thường, nên không có vấn đề. Nhưng khi dữ liệu có nhiều dấu, thứ tự có thể khác mong đợi. Đây là lý do các hệ thống thật thường dùng thêm cột sort_name đã chuẩn hóa.
Ba lần thử thường gặp:
Lần 1 — quên WHERE:
SELECT name FROM customers ORDER BY name;Trả 12 dòng. Bài chấm báo thừa dòng. Cách sửa không phải là thêm LIMIT 3 — điều đó chỉ đúng với bộ dữ liệu hiển thị và sai ngay trên bộ ẩn. Phải thêm đúng điều kiện lọc.
Lần 2 — sai dấu:
SELECT name FROM customers WHERE city = 'Ha Noi' ORDER BY name;Trả 0 dòng. Ha Noi khác Hà Nội ở hai dấu. Bài chấm báo thiếu toàn bộ. Cách sửa: dùng đúng chuỗi trong dữ liệu, hoặc kiểm tra bằng SELECT DISTINCT city FROM customers; trước khi viết điều kiện.
Lần 3 — dùng LIKE quá rộng:
SELECT name FROM customers WHERE city LIKE 'Hà%' ORDER BY name;Trên bộ dữ liệu hiển thị, kết quả vẫn đúng ba dòng vì chỉ có Hà Nội bắt đầu bằng Hà. Nhưng nếu bộ ẩn có thêm thành phố Hà Tĩnh, truy vấn sẽ trả thừa. Đề nói city = 'Hà Nội', không nói "bắt đầu bằng Hà". Dùng = khi đề cho giá trị chính xác; chỉ dùng LIKE khi đề yêu cầu mẫu.
Ba lần thử này minh họa một nguyên tắc: đề bài là hợp đồng. Kết quả đúng trên dữ liệu hiển thị chưa đủ; truy vấn phải diễn đạt đúng quy tắc để đúng trên mọi bộ dữ liệu cùng cấu trúc.
Ví dụ chạy được
Trước khi nộp, kiểm tra dữ liệu nguồn:
SELECT DISTINCT city FROM customers ORDER BY city;Kết quả có năm thành phố: Cần Thơ, Hà Nội, Hải Phòng, TP. Hồ Chí Minh, Đà Nẵng. Việc này xác nhận chuỗi cần dùng là 'Hà Nội', không phải 'Hà nội' hay 'Ha Noi'.
Sau đó chạy đáp án:
SELECT name
FROM customers
WHERE city = 'Hà Nội'
ORDER BY name;Ba dòng như bảng ở trên. Đối chiếu thủ công: trong 12 khách, những ai có city là Hà Nội? An Nguyễn (dòng 1), Dũng Phạm (dòng 4), Khánh Hồ (dòng 9). Đúng ba người. Nếu kết quả có bốn dòng, có thể bạn đã dùng LIKE và khớp nhầm thành phố khác; nếu có hai dòng, có thể điều kiện bị viết thành city = 'Hà Nội' AND segment = 'retail' và loại Dũng, Khánh.
Một biến thể để tự kiểm tra hiểu bài:
SELECT name, city
FROM customers
WHERE city = 'Hà Nội'
ORDER BY name;Thêm cột city không làm thay đổi số dòng, nhưng giúp nhìn thấy lý do từng dòng được chọn. Khi gỡ lỗi, luôn thêm cột đang lọc vào SELECT — nó biến một kết quả trừu tượng thành bằng chứng cụ thể.
Cuối cùng, thử truy vấn "gần đúng" để thấy bài chấm phản ứng:
SELECT name
FROM customers
WHERE city = 'Hà Nội';Kết quả vẫn ba dòng, nhưng thiếu ORDER BY. Trên máy bạn, thứ tự có thể trùng với đáp án. Trên bộ ẩn, thứ tự có thể khác. Bài chấm so sánh chính xác nên sẽ báo sai thứ tự — một lời nhắc rằng "chạy được" và "đúng đề" là hai chuyện khác nhau.
Thực hành
- Nộp đáp án cho bài Khách hàng ở Hà Nội (
filter-hanoi). Trước khi nộp, tự đếm số dòng mong đợi và ghi ra giấy. - Làm một biến thể không chấm điểm: lấy
namevàsegmentcủa khách ở Đà Nẵng, sắp theo tên. Kết quả hai dòng: Chi Lê, Linh Ngô. - Viết truy vấn lấy khách ở Hà Nội hoặc Đà Nẵng, sắp theo thành phố rồi theo tên. So sánh số dòng với tổng của hai truy vấn riêng lẻ.
- Tự đặt đề tương tự cho bảng
products, ví dụ "lấy tên sản phẩm thuộc nhóm Điện tử, sắp theo giá giảm dần". Viết ra giấy trước, rồi chạy để đối chiếu.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| Chấm báo thừa dòng | Thiếu WHERE hoặc dùng LIKE quá rộng | Dùng đúng = với giá trị đề cho |
| Chấm báo thiếu toàn bộ | Sai dấu hoặc sai hoa/thường | Kiểm tra SELECT DISTINCT city |
| Chấm báo sai thứ tự | Thiếu ORDER BY name | Thêm đúng cột sắp xếp đề yêu cầu |
| Đúng trên dữ liệu hiển thị, sai trên bộ ẩn | Hardcode danh sách kết quả | Viết quy tắc lọc, không liệt kê tên |
| Chọn thừa cột | Dùng SELECT * hoặc thêm cột ngoài đề | Chỉ chọn name như đề yêu cầu |
Lỗi thứ tư là lỗi khó tự phát hiện nhất, vì màn hình không báo gì. Cách phòng tránh: sau khi đạt bài, tự hỏi "nếu dữ liệu có thêm một dòng phù hợp, truy vấn của mình có trả đúng không?". Nếu câu trả lời là không, bạn đã hardcode ở đâu đó.
Tóm tắt
- Đề bài cho giá trị chính xác thì dùng
=, không dùngLIKE. - Chọn đúng cột, đúng điều kiện, đúng thứ tự — cả ba đều được chấm.
- Kiểm tra chuỗi bằng
SELECT DISTINCTtrước khi viếtWHERE. - Truy vấn đúng phải đúng trên cả bộ dữ liệu ẩn, không chỉ bộ hiển thị.
- Thêm cột đang lọc vào
SELECTkhi gỡ lỗi để nhìn thấy bằng chứng.
Bạn đã đi hết chương lọc dữ liệu: WHERE, so sánh số, chuỗi, ngày, AND/OR và NULL. Chương tiếp theo chuyển sang sắp xếp và giới hạn — nơi kết quả bắt đầu có thứ tự và quy mô mà người đọc mong đợi.
Use ← → to move between lessons