Bây giờ bạn đã sẵn sàng lặn sâu vào thế giới ví dụ thực tế để xem mọi thứ hoạt động thế nào trong các bài toán đời thường nhé!
Ví dụ: tính rank doanh số theo vùng
Giả sử mình có bảng sales, chứa dữ liệu về doanh số ở các vùng khác nhau. Nhiệm vụ là xác định rank doanh số cho từng vùng.
| id | region | sales_amount |
|---|---|---|
| 1 | North | 5000 |
| 2 | North | 3000 |
| 3 | North | 7000 |
| 4 | South | 2000 |
| 5 | South | 4000 |
| 6 | East | 8000 |
| 7 | East | 6000 |
Bài toán: tìm rank (RANK) doanh số cho từng vùng
SELECT
region,
sales_amount,
RANK() OVER (PARTITION BY region ORDER BY sales_amount DESC) AS sales_rank
FROM
sales;
Kết quả:
| region | sales_amount | sales_rank |
|---|---|---|
| North | 7000 | 1 |
| North | 5000 | 2 |
| North | 3000 | 3 |
| South | 4000 | 1 |
| South | 2000 | 2 |
| East | 8000 | 1 |
| East | 6000 | 2 |
Lưu ý là mình dùng PARTITION BY region để tính rank riêng cho từng vùng. Nếu không dùng PARTITION BY thì rank sẽ tính toàn bộ bảng luôn.
Ví dụ: tính tổng tích lũy doanh thu
Giờ thử xử lý bảng transactions để tính tổng tích lũy (cumulative sum) doanh thu cho từng khách hàng nhé.
| id | customer_id | purchase_date | amount |
|---|---|---|---|
| 1 | 101 | 2023-01-01 | 100 |
| 2 | 101 | 2023-01-03 | 50 |
| 3 | 102 | 2023-01-02 | 200 |
| 4 | 101 | 2023-01-05 | 150 |
| 5 | 102 | 2023-01-04 | 100 |
Bài toán: tính tổng tích lũy cho từng khách hàng
SELECT
customer_id,
purchase_date,
amount,
SUM(amount) OVER (PARTITION BY customer_id ORDER BY purchase_date) AS cumulative_sum
FROM
transactions;
Kết quả:
| customer_id | purchase_date | amount | cumulative_sum |
|---|---|---|---|
| 101 | 2023-01-01 | 100 | 100 |
| 101 | 2023-01-03 | 50 | 150 |
| 101 | 2023-01-05 | 150 | 300 |
| 102 | 2023-01-02 | 200 | 200 |
| 102 | 2023-01-04 | 100 | 300 |
Điểm mấu chốt ở đây là dùng ORDER BY purchase_date trong OVER() để tổng tích lũy được tính theo thứ tự thời gian.
Ví dụ: chia dữ liệu thành các quantile
Giả sử mình có bảng students, trong đó có tên và điểm kiểm tra. Mình muốn chia học sinh thành 4 nhóm dựa trên điểm số.
| id | name | test_score |
|---|---|---|
| 1 | Alice | 85 |
| 2 | Bob | 95 |
| 3 | Charlie | 75 |
| 4 | Diana | 88 |
| 5 | Edward | 65 |
| 6 | Fiona | 70 |
Bài toán: chia học sinh thành 4 nhóm dùng NTILE()
SELECT
name,
test_score,
NTILE(4) OVER (ORDER BY test_score DESC) AS quartile
FROM
students;
Kết quả truy vấn sẽ như này:
| name | test_score | quartile |
|---|---|---|
| Bob | 95 | 1 |
| Diana | 88 | 1 |
| Alice | 85 | 2 |
| Charlie | 75 | 3 |
| Fiona | 70 | 3 |
| Edward | 65 | 4 |
NTILE(4) chia dữ liệu thành 4 nhóm. Học sinh có điểm cao nhất sẽ vào nhóm đầu, điểm thấp nhất vào nhóm cuối.
Ví dụ: phân tích dữ liệu thời gian
Trong bảng site_visits lưu dữ liệu về số lượt truy cập site theo ngày. Nhiệm vụ là tính chênh lệch số lượt truy cập giữa các ngày cho từng site.
| site_id | visit_date | visits |
|---|---|---|
| 1 | 2023-01-01 | 100 |
| 1 | 2023-01-02 | 120 |
| 1 | 2023-01-03 | 110 |
| 2 | 2023-01-01 | 50 |
| 2 | 2023-01-02 | 60 |
| 2 | 2023-01-03 | 70 |
Bài toán — tính chênh lệch lượt truy cập giữa các ngày
SELECT
site_id,
visit_date,
visits,
visits - LAG(visits) OVER (PARTITION BY site_id ORDER BY visit_date) AS visit_diff
FROM
site_visits;
Kết quả:
| site_id | visit_date | visits | visit_diff |
|---|---|---|---|
| 1 | 2023-01-01 | 100 | NULL |
| 1 | 2023-01-02 | 120 | 20 |
| 1 | 2023-01-03 | 110 | -10 |
| 2 | 2023-01-01 | 50 | NULL |
| 2 | 2023-01-02 | 60 | 10 |
| 2 | 2023-01-03 | 70 | 10 |
Hàm LAG() cho phép lấy giá trị từ dòng trước đó. Nếu không có dữ liệu dòng trước thì kết quả sẽ là NULL. Chi tiết về nó bạn sẽ học ở mấy bài sau nha :P
GO TO FULL VERSION