# 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ê:

1. order\_items có product\_id không tồn tại
2. 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:

1. Nên index những cột nào?
2. Vì sao không nên tính tổng tiền từ orders.total\_amount nếu có order\_items?

---