DHDataHọc
PracticeLesson 12/306 min read+20 XP

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 WHERE hoà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 name củ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ỏiTrả lờiThành phần SQL
Bảng nào?customersFROM customers
Cột nào?Chỉ nameSELECT name
Lọc gì?city = 'Hà Nội'WHERE city = 'Hà Nội'
Thứ tự?Theo tênORDER BY name
Giới hạn?Khôngkhông có LIMIT

Ghép lại:

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

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

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

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

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

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

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

code
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

  1. 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.
  2. Làm một biến thể không chấm điểm: lấy name và segment của khách ở Đà Nẵng, sắp theo tên. Kết quả hai dòng: Chi Lê, Linh Ngô.
  3. 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ẻ.
  4. 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ứngNguyên nhânCách sửa
Chấm báo thừa dòngThiếu WHERE hoặc dùng LIKE quá rộngDùng đúng = với giá trị đề cho
Chấm báo thiếu toàn bộSai dấu hoặc sai hoa/thườngKiểm tra SELECT DISTINCT city
Chấm báo sai thứ tựThiếu ORDER BY nameThê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ộ ẩnHardcode 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ộtDù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ùng LIKE.
  • 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 DISTINCT trước khi viết WHERE.
  • 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 SELECT khi 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