Bài tập SQL
Bài tập SQL từ cơ bản đến nâng cao
- BÀI SQL Cơ bản – CHỦ ĐỀ: HỆ THỐNG BÁN HÀNG / ĐƠN HÀNG
- ĐỀ TEST SQL – CHỦ ĐỀ: QUẢN LÝ SINH VIÊN
- ĐỀ TEST SQL – CHỦ ĐỀ: QUẢN LÝ Y TẾ
BÀI SQL Cơ bản – CHỦ ĐỀ: HỆ THỐNG BÁN HÀNG / ĐƠN HÀNG
Bảng users
users (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
full_name VARCHAR(100),
email VARCHAR(100),
department_id BIGINT,
status INT, -- 1: active, 0: inactive
created_at TIMESTAMP
)
Bảng departments
departments (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
)
Bảng documents
documents (
id BIGINT PRIMARY KEY,
title VARCHAR(255),
creator_id BIGINT,
status VARCHAR(20), -- draft, processing, completed
created_at TIMESTAMP
)
Bảng document_logs
document_logs (
id BIGINT PRIMARY KEY,
document_id BIGINT,
action VARCHAR(50), -- create, approve, reject, view
user_id BIGINT,
created_at TIMESTAMP
)
Bài test
⏱ Thời gian gợi ý: 30–40 phút
🎯 Mục tiêu:
-
SELECT, WHERE
-
JOIN cơ bản
-
COUNT, GROUP BY
-
ORDER BY
-
Hiểu dữ liệu nghiệp vụ
Câu 1: Lấy danh sách user đang hoạt động
Yêu cầu:
Lấy username, full_name, email của user có status = 1
Câu 2: User theo phòng ban
Yêu cầu:
Lấy danh sách user kèm tên phòng ban, sắp xếp theo tên phòng ban tăng dần
Câu 3: Đếm số user theo phòng ban
Yêu cầu:
Mỗi phòng ban có bao nhiêu user (chỉ tính user active)
Output:
department_name | total_users
Câu 4: Văn bản do user tạo
Yêu cầu:
Lấy danh sách văn bản (title, created_at) do user có username = 'admin' tạo
Câu 5: Thống kê văn bản theo trạng thái
Yêu cầu:
Đếm số văn bản theo từng status
Tiêu chí pass Cơ bản
-
Viết được SELECT đúng
-
JOIN không sai logic
-
Không dùng SELECT *
-
Kết quả đúng nghiệp vụ
BÀI TEST SQL – CHỦ ĐỀ: HỆ THỐNG BÁN HÀNG / ĐƠN HÀNG
I. MÔ TẢ CHUNG
Giả định CSDL: MySQL / PostgreSQL
1️⃣ Bảng customers
customers (
id BIGINT PRIMARY KEY,
customer_code VARCHAR(50),
full_name VARCHAR(100),
email VARCHAR(100),
status INT, -- 1: active, 0: inactive
created_at TIMESTAMP
)
2️⃣ Bảng products
products (
id BIGINT PRIMARY KEY,
product_code VARCHAR(50),
name VARCHAR(255),
price DECIMAL(12,2),
status INT -- 1: selling, 0: stopped
)
3️⃣ Bảng orders
orders (
id BIGINT PRIMARY KEY,
order_code VARCHAR(50),
customer_id BIGINT,
order_date TIMESTAMP,
status VARCHAR(20) -- new, paid, cancelled, completed
)
4️⃣ Bảng order_items
order_items (
id BIGINT PRIMARY KEY,
order_id BIGINT,
product_id BIGINT,
quantity INT,
unit_price DECIMAL(12,2)
)
5️⃣ Bảng payment_logs
payment_logs (
id BIGINT PRIMARY KEY,
order_id BIGINT,
payment_method VARCHAR(50), -- cash, bank, momo
amount DECIMAL(12,2),
payment_time TIMESTAMP
)
II. BÀI TEST SQL – MỨC ĐỘ CƠ BẢN
⏱ Thời gian: 30–40 phút
🎯 Mục tiêu:
-
SELECT, WHERE
-
JOIN cơ bản
-
COUNT, SUM
-
GROUP BY
-
Hiểu nghiệp vụ bán hàng
🟢 Câu 1: Khách hàng đang hoạt động
Yêu cầu:
Lấy danh sách customer_code, full_name, email của khách hàng có status = 1
🟢 Câu 2: Danh sách đơn hàng kèm tên khách hàng
Yêu cầu:
Lấy order_code, order_date, status, full_name
Sắp xếp theo order_date giảm dần
🟢 Câu 3: Thống kê số đơn theo trạng thái
Yêu cầu:
Đếm số lượng đơn theo từng status
🟢 Câu 4: Sản phẩm trong một đơn hàng
Yêu cầu:
Với order_code = 'ORD001', liệt kê:
product_code | product_name | quantity | unit_price
🟢 Câu 5: Tổng tiền của mỗi đơn hàng
Yêu cầu:
Tính tổng tiền = SUM(quantity * unit_price) cho từng đơn hàng
✅ Tiêu chí pass Cơ bản
-
JOIN đúng
-
Tính toán chính xác
-
Không lạm dụng SELECT *
III. BÀI TEST SQL – MỨC ĐỘ NÂNG CAO
⏱ Thời gian: 60–90 phút
🎯 Mục tiêu:
-
Subquery
-
LEFT JOIN / NOT EXISTS
-
Kiểm thử dữ liệu
-
Phát hiện sai lệch nghiệp vụ
-
SQL tối ưu
🔵 Câu 1: Khách hàng chưa từng đặt đơn
Yêu cầu:
Liệt kê khách hàng chưa có bất kỳ order nào
🔵 Câu 2: Đơn hàng chưa được thanh toán
Yêu cầu:
Lấy danh sách đơn hàng không có bản ghi trong payment_logs
🔵 Câu 3: Đơn hàng có tổng tiền khác tổng thanh toán
Yêu cầu:
Phát hiện các đơn hàng mà:
SUM(order_items) ≠ SUM(payment_logs.amount)
➡️ Mục tiêu: kiểm thử sai lệch dữ liệu tài chính
🔵 Câu 4: Sản phẩm bán chạy nhất
Yêu cầu:
Tìm sản phẩm có tổng số lượng bán ra cao nhất
(Chỉ tính đơn status = 'completed')
🔵 Câu 5: Lần mua gần nhất của mỗi khách hàng
Yêu cầu:
Với mỗi khách hàng, lấy đơn hàng mới nhất
Output:
customer_code | full_name | last_order_date
➡️ Gợi ý:
-
MAX(order_date)
-
CTE hoặc subquery
🔵 Câu 6: Phát hiện dữ liệu bất thường
Yêu cầu:
Liệt kê:
-
order_items có product_id không tồn tại
-
orders có customer_id không tồn tại
➡️ Mục tiêu: Data Integrity Testing
🔵 Câu 7 (Bonus – Tư duy hệ thống)
Câu hỏi lý thuyết:
-
Nên index những cột nào?
-
Vì sao không nên tính tổng tiền từ orders.total_amount nếu có order_items?
ĐỀ TEST SQL – CHỦ ĐỀ: QUẢN LÝ SINH VIÊN
⏱ Thời gian làm bài: 90 phút
🎯 Mục tiêu đánh giá:
● Viết SQL chính xác
● Hiểu nghiệp vụ giáo dục
● Phát hiện dữ liệu bất thường
● Tư duy kiểm thử dữ liệu
I. MÔ TẢ HỆ THỐNG & CSDL
Giả định DB: MySQL / PostgreSQL
1️⃣ Bảng students
students (
id BIGINT PRIMARY KEY,
student_code VARCHAR(20),
full_name VARCHAR(100),
gender VARCHAR(10), -- male, female
date_of_birth DATE,
class_id BIGINT,
status VARCHAR(20), -- studying, graduated, dropped
created_at TIMESTAMP
)
2️⃣ Bảng classes
classes (
id BIGINT PRIMARY KEY,
class_code VARCHAR(20),
class_name VARCHAR(100),
department VARCHAR(100)
)
3️⃣ Bảng subjects
subjects (
id BIGINT PRIMARY KEY,
subject_code VARCHAR(20),
subject_name VARCHAR(100),
credit INT
)
4️⃣ Bảng enrollments
enrollments (
id BIGINT PRIMARY KEY,
student_id BIGINT,
subject_id BIGINT,
semester VARCHAR(20), -- 2024-1, 2024-2
score DECIMAL(4,2)
)
5️⃣ Bảng attendance_logs
attendance_logs (
id BIGINT PRIMARY KEY,
student_id BIGINT,
subject_id BIGINT,
attend_date DATE,
status VARCHAR(20) -- present, absent
)
II. PHẦN A – SQL CƠ BẢN
⏱ Thời gian gợi ý: 35–40 phút
🟢 Câu 1: Danh sách sinh viên đang học
Yêu cầu:
Lấy student_code, full_name, gender, status của sinh viên có status = 'studying'
🟢 Câu 2: Sinh viên và lớp học
Yêu cầu:
Lấy danh sách sinh viên kèm class_code, class_name
🟢 Câu 3: Số sinh viên theo khoa
Yêu cầu:
Thống kê số lượng sinh viên theo department
🟢 Câu 4: Môn học mà sinh viên đăng ký
Yêu cầu:
Với student_code = 'SV001', liệt kê:
subject_code | subject_name | semester | score
🟢 Câu 5: Điểm trung bình của mỗi sinh viên
Yêu cầu:
Tính điểm trung bình (AVG) của từng sinh viên
✅ Tiêu chí pass Cơ bản
● JOIN đúng
● GROUP BY chính xác
● Không SELECT *
● SQL chạy được
III. PHẦN B – SQL NÂNG CAO
⏱ Thời gian gợi ý: 50–55 phút
🔵 Câu 6: Sinh viên chưa đăng ký môn học nào
Yêu cầu:
Liệt kê sinh viên không có bản ghi trong enrollments
🔵 Câu 7: Sinh viên trượt môn
Yêu cầu:
Liệt kê sinh viên có bất kỳ môn nào có score < 5
🔵 Câu 8: Môn học có số sinh viên đăng ký nhiều nhất
Yêu cầu:
Tìm môn học có số lượng sinh viên đăng ký cao nhất
🔵 Câu 9: Lần điểm danh gần nhất của mỗi sinh viên
Yêu cầu:
Với mỗi sinh viên, lấy bản ghi điểm danh mới nhất (ngày & trạng thái)
🔵 Câu 10: Phát hiện dữ liệu bất thường
Yêu cầu:
Liệt kê:
- enrollments có student_id không tồn tại
- attendance_logs có subject_id không tồn tại
➡️ Mục tiêu: Data Integrity Testing
🔵 Câu 11 (Bonus – Tư duy hệ thống)
Câu hỏi ngắn:
- Nên index những cột nào?
- Vì sao không nên lưu điểm trung bình sẵn trong bảng students?
ĐỀ TEST SQL – CHỦ ĐỀ: QUẢN LÝ Y TẾ
Thời gian làm bài: 90 phút
🎯 Mục tiêu đánh giá:
- Viết SQL chính xác
- Hiểu nghiệp vụ y tế
- Phát hiện dữ liệu bất thường
- Tư duy kiểm thử dữ liệu
I. MÔ TẢ HỆ THỐNG & CSDL
Giả định DB: MySQL / PostgreSQL
1️⃣ Bảng patients
patients (
id BIGINT PRIMARY KEY,
patient_code VARCHAR(20),
full_name VARCHAR(100),
gender VARCHAR(10),
date_of_birth DATE,
phone VARCHAR(20),
status VARCHAR(20),
created_at TIMESTAMP
)
2️⃣ Bảng doctors
doctors (
id BIGINT PRIMARY KEY,
doctor_code VARCHAR(20),
full_name VARCHAR(100),
specialty VARCHAR(100),
department VARCHAR(100),
status VARCHAR(20)
)
3️⃣ Bảng appointments
appointments (
id BIGINT PRIMARY KEY,
patient_id BIGINT,
doctor_id BIGINT,
appointment_date DATE,
appointment_time TIME,
status VARCHAR(20)
)
4️⃣ Bảng medical_records
medical_records (
id BIGINT PRIMARY KEY,
patient_id BIGINT,
doctor_id BIGINT,
diagnosis TEXT,
visit_date DATE,
note TEXT
)
5️⃣ Bảng prescriptions
prescriptions (
id BIGINT PRIMARY KEY,
medical_record_id BIGINT,
medicine_name VARCHAR(100),
dosage VARCHAR(50),
days INT
)
II. PHẦN A – SQL CƠ BẢN
⏱ Thời gian gợi ý: 35–40 phút
Câu 1: Danh sách bệnh nhân đang hoạt động
Lấy patient_code, full_name, gender, status của bệnh nhân có status = 'active'.
Câu 2: Lịch hẹn khám và bác sĩ
Liệt kê patient_code, patient_name, doctor_name, specialty, appointment_date, status.
Câu 3: Số lượng bác sĩ theo khoa
Thống kê số lượng bác sĩ theo department.
Câu 4: Lịch sử khám của bệnh nhân
Với patient_code = 'BN001', liệt kê visit_date, doctor_name, diagnosis.
Câu 5: Số lượt khám của mỗi bệnh nhân
Đếm số bản ghi medical_records của từng bệnh nhân.
III. PHẦN B – SQL NÂNG CAO
⏱ Thời gian gợi ý: 50–55 phút
Câu 6: Bệnh nhân chưa từng đi khám
Liệt kê bệnh nhân không có bản ghi trong medical_records.
Câu 7: Bác sĩ có lịch hẹn bị hủy
Liệt kê bác sĩ có ít nhất 1 lịch hẹn status = 'canceled'.
Câu 8: Bác sĩ khám nhiều bệnh nhân nhất
Tìm bác sĩ có số lượt khám nhiều nhất.
Câu 9: Lần khám gần nhất của mỗi bệnh nhân
Lấy patient_code, last_visit_date, doctor_name, diagnosis.
Câu 10: Phát hiện dữ liệu bất thường
Liệt kê appointments có patient_id không tồn tại và prescriptions có medical_record_id không tồn tại.
Câu 11 (Bonus): Tư duy hệ thống
1. Nên index những cột nào?
2. Vì sao không nên lưu tổng số lượt khám trong bảng patients?