Trang chủ · Blog về kiểm thử ·

SQL cho QA: câu truy vấn, kiểm tra cơ sở dữ liệu và bài phỏng vấn

SQL hữu ích khi trả lời một câu hỏi sản phẩm: order đã được lưu chưa, retry có tạo duplicate không, customer nào không có activity, và lỗi giữa chừng có để lại dữ liệu dở dang không? Bài này giải các câu hỏi đó trên một schema nhỏ thay vì liệt kê lệnh thiếu ngữ cảnh.

Quy trình kiểm tra database có thể lặp lại
  1. Nêu business invariant
  2. Đọc schema và relationship
  3. Dự đoán expected rows
  4. Chạy read-only query và so sánh
Schema mẫu dùng trong mọi ví dụ
Table Column quan trọng Business meaning
customersid, email, owner_id, created_atCustomer CRM và manager phụ trách
ordersid, customer_id, status, total, created_atOrder và trạng thái hiện tại
paymentsid, order_id, external_id, status, amountKết quả payment attempt bên ngoài
activitiesid, customer_id, kind, created_atCall, email hoặc meeting trong CRM

1. Đọc schema trước khi viết SQL

Tên table không mô tả đầy đủ dữ liệu. Hãy hỏi primary key, foreign key, column nào nullable, status nào hợp lệ và uniqueness có được database bảo vệ không. Thiếu các thông tin này, một query trông hợp lý vẫn có thể trả lời sai câu hỏi.

Trong schema mẫu, orders.customer_id và activities.customer_id trỏ tới customers.id; payments.order_id trỏ tới orders.id. Một customer có nhiều order và activity; một order có thể có nhiều payment attempt. Cardinality này giải thích vì sao JOIN có thể nhân số row.

  • Viết relationship bằng lời trước khi JOIN.
  • Phân biệt row không tồn tại với field có NULL.
  • Xác nhận timezone và soft-delete rule.
Tự giải trước khi xem lại

Giải thích vì sao một order có nhiều payment row và cần so sánh gì để chứng minh double charge.

2. SELECT và WHERE: xác minh chính xác một thao tác

Sau POST /orders trả 201, đừng chỉ tìm theo status chung chung. Lưu order id từ response và query đúng record đó. So customer_id, status, total và created_at với request và contract. Chọn rõ column giúp evidence dễ đọc và tránh lấy dữ liệu không liên quan.

Time window hữu ích khi không có id nhưng yếu hơn vì test khác có thể tạo row tương tự. ORDER BY không lọc record; LIMIT thiếu deterministic order có thể trả row khác ở lần chạy sau.

Xác minh order do API tạo
SELECT id, customer_id, status, total, created_at
FROM orders
WHERE id = 1842 AND customer_id = 77;
Tự giải trước khi xem lại

Viết query lấy paid orders của customer 77 từ 2026-10-01, mới nhất trước. Dự đoán column trước khi chạy.

3. JOIN: so sánh các business object liên quan

INNER JOIN chỉ trả pair có match ở hai bên. LEFT JOIN giữ mọi row phía trái và điền NULL cho phía phải bị thiếu. Khác biệt này rất quan trọng khi tìm customer không có order hoặc order không có payment.

Filter của right table trong WHERE có thể loại NULL và biến LEFT JOIN thành INNER JOIN. Với “customer không có paid order”, đặt status trong ON rồi kiểm joined order id IS NULL.

Customer không có paid order
SELECT c.id, c.email
FROM customers c
LEFT JOIN orders o
  ON o.customer_id = c.id AND o.status = 'paid'
WHERE o.id IS NULL
ORDER BY c.id;
Tự giải trước khi xem lại

Tìm order hoàn toàn không có payment row. Chọn left table và id cần bằng NULL.

4. NULL, empty string và missing data không giống nhau

NULL là giá trị chưa biết hoặc vắng mặt. Nó không bằng empty string và không kiểm bằng = NULL; phải dùng IS NULL. Trong sản phẩm, NULL, empty và whitespace có thể đi qua các validation path khác nhau.

Comparison với NULL cho kết quả unknown, nên WHERE không pass. COALESCE tiện cho report nhưng dùng quá sớm có thể che defect bằng cách đổi NULL bất ngờ thành default trông có vẻ hợp lệ.

Ba trạng thái email vắng mặt
SELECT id, email,
  CASE
    WHEN email IS NULL THEN 'null'
    WHEN TRIM(email) = '' THEN 'blank'
    ELSE 'present'
  END AS email_state
FROM customers;
Tự giải trước khi xem lại

Thiết kế check riêng cho NULL, empty string và ba dấu cách trong customers.email, kèm expected behavior.

5. COUNT, GROUP BY và HAVING: tìm duplicate và total sai

GROUP BY tạo group; COUNT, SUM, MIN, MAX tính trong group; HAVING lọc group sau aggregate. WHERE lọc source row trước đó. Nhầm các bước này là lỗi interview phổ biến.

COUNT(*) đếm row, COUNT(column) bỏ NULL. JOIN nhiều quan hệ one-to-many có thể nhân row và làm total tăng sai. Hãy aggregate child table trước thay vì dùng DISTINCT như một bản vá không giải thích được.

Duplicate email và payment reference
SELECT LOWER(TRIM(email)) AS normalized_email, COUNT(*) AS customer_count
FROM customers
WHERE email IS NOT NULL
GROUP BY LOWER(TRIM(email))
HAVING COUNT(*) > 1;

SELECT external_id, COUNT(*) AS attempts, SUM(amount) AS charged
FROM payments
WHERE status = 'succeeded'
GROUP BY external_id
HAVING COUNT(*) > 1;
Tự giải trước khi xem lại

Trả customer có hơn ba activities trong tháng 10/2026, gồm customer id và count, sắp xếp count giảm dần.

6. Kiểm data integrity, không chỉ API response

Success response không chứng minh related data nhất quán. Order có thể thiếu line, payment có thể trỏ tới order không tồn tại, hoặc hai customer dùng email đáng lẽ unique. Foreign key, UNIQUE và CHECK bảo vệ database, nhưng application vẫn phải xử lý lỗi constraint đúng contract.

Tìm orphan row là kỹ thuật chẩn đoán, không phải quyền đọc tùy ý production data. Dùng synthetic records, chọn ít column và đính kèm identifier thay vì personal data đầy đủ.

Orphan payment và succeeded amount không hợp lệ
SELECT p.id, p.order_id
FROM payments p
LEFT JOIN orders o ON o.id = p.order_id
WHERE o.id IS NULL;

SELECT id, order_id, amount
FROM payments
WHERE status = 'succeeded' AND amount <= 0;
Tự giải trước khi xem lại

Nêu ba invariant cho orders/payments và một read-only query có thể tìm violation cho mỗi invariant.

7. Transaction, retry và concurrency

Transaction gom các thay đổi để cùng commit hoặc cùng rollback. Hãy test failure giữa hai write liên quan: payment thành công nhưng update order thất bại thì state nào còn lại và reconciliation chạy thế nào?

Concurrent request lộ defect mà sequential check bỏ sót. Hai lần convert lead hoặc retry sau timeout có thể cùng pass kiểm tra “đã tồn tại chưa?”. Unique constraint, idempotency key hoặc locking phải giữ business invariant.

Evidence cho retry không được double charge
SELECT order_id, external_id, status, amount, created_at
FROM payments
WHERE order_id = 1842
ORDER BY created_at, id;
Tự giải trước khi xem lại

Mô tả hai request song song có thể tạo duplicate customer từ một CRM lead. Nêu invariant và database evidence mong đợi.

8. Cách giải bài SQL trong phỏng vấn

Đừng gõ ngay. Hãy diễn đạt task bằng business language, nêu table cần giữ, vẽ relationship và dự đoán một vài row. Sau khi viết query, kiểm bằng suy nghĩ với zero, one và many child rows.

Câu trả lời Middle còn nêu limitation: duplicate source data, timezone boundary, soft deletion, isolation và quyền direct DB access. Hỏi schema là bình thường; tự bịa column và cardinality mới nguy hiểm.

  • Giải thích từng JOIN condition.
  • Nêu khả năng duplicate output row.
  • Kiểm empty input và nhiều child rows.
  • Tách diagnostic SELECT khỏi cleanup script.
  • Không chạy UPDATE/DELETE chỉ để tỏ ra tự tin.
Tự giải trước khi xem lại

Chuẩn bị câu trả lời nói trong năm phút và hai query. Đổi requirement từ “không có order” thành “không có paid order” rồi giải thích JOIN thay đổi thế nào.

Câu hỏi thường gặp về SQL cho QA

Manual QA có cần SQL phức tạp không?

Phần lớn công việc Junior bắt đầu bằng SELECT read-only: filter, JOIN, NULL và aggregate. Mức độ phụ thuộc sản phẩm. Gắn query với business invariant quan trọng hơn thuộc cú pháp nâng cao thiếu ngữ cảnh.

QA có thể chạy UPDATE hoặc DELETE không?

Chỉ trong environment được duyệt, với permission và cleanup plan rõ ràng. Điều tra production thường dùng read-only access. Không ứng biến destructive SQL trong interview hoặc incident.

Database result có thay API check không?

Không. API chứng minh external contract; database cung cấp evidence về stored state. Khi risk cần, hãy so cả hai và nhớ internal schema có thể thay đổi.

SQL topic nào hay gặp trong QA interview?

SELECT/WHERE, INNER và LEFT JOIN, NULL, COUNT, GROUP BY, HAVING, duplicate, subquery và transaction thường xuất hiện. Scope tùy công ty nên hãy hỏi recruiter về database và format.

SQL không phải tập hợp câu thần chú cho interview. Nó là cách biến product rule thành evidence chính xác về data. Bắt đầu từ expected rows, giữ query read-only và nói rõ kết quả chứng minh hay chưa chứng minh điều gì.

Yêu cầu quyền truy cập miễn phí để thực hành QA Bài tiếp theo

← Tất cả bài viết