Bài 1: Giới thiệu về Trình quản lý quảng cáo

🎓 Bài thực hành SQL – Truy vấn nhiều bảng trong hệ thống khóa học

💡 Mục tiêu bài học

  • Kết hợp nhiều bảng bằng JOIN

  • Sử dụng truy vấn con trong SELECT, WHEREFROM

  • Ứng dụng GROUP BY để tổng hợp dữ liệu

🧩 Các bảng liên quan

Bảng Mục đích
KhoaHoc Chứa thông tin khóa học
ChuDe Danh sách chủ đề của khóa học
Video Danh sách video thuộc mỗi khóa học
DangKyKhoaHoc Thông tin học viên đăng ký khóa học

🧩 Bổ sung bảng :  

DangKyKhoaHoc
#ID int
idHocVien int
idKhoaHoc int
ThoiGianDangKy datetime
HocPhi float
idNhanVienXacNhan int
ThoiGianXacNhan datetime

THỰC HÀNH

1. Lấy danh sách học viên đã đăng ký và thông tin khóa học tương ứng

SELECT 
    dkh.idHocVien,
    kh.TenKhoaHoc,
    dkh.ThoiGianDangKy,
    dkh.HocPhi
FROM DangKyKhoaHoc dkh
JOIN KhoaHoc kh ON dkh.idKhoaHoc = kh.ID;

📌 Giải thích: Dùng JOIN để lấy tên khóa học từ bảng KhoaHoc, liên kết qua idKhoaHoc.

2. Lấy danh sách tất cả khóa học và tổng số lượt đăng ký

SELECT 
    kh.TenKhoaHoc,
    COUNT(dkh.ID) AS SoLuotDangKy
FROM KhoaHoc kh
LEFT JOIN DangKyKhoaHoc dkh ON kh.ID = dkh.idKhoaHoc
GROUP BY kh.TenKhoaHoc;

📌 Giải thích:

  • Dùng LEFT JOIN để vẫn hiển thị các khóa học chưa có lượt đăng ký.

  • GROUP BY để tính tổng lượt đăng ký theo khóa.

3. Truy vấn con trong SELECT: Tổng học phí từng học viên đã đóng

SELECT 
    idHocVien,
    (SELECT SUM(HocPhi) 
     FROM DangKyKhoaHoc dkh2 
     WHERE dkh2.idHocVien = dkh1.idHocVien
    ) AS TongTienDaDong
FROM DangKyKhoaHoc dkh1
GROUP BY idHocVien;

📌 Giải thích: Dùng truy vấn con để tính tổng học phí của mỗi học viên.

4. Truy vấn con trong WHERE: Lọc ra các đăng ký có học phí cao hơn trung bình

SELECT * 
FROM DangKyKhoaHoc
WHERE HocPhi > (
    SELECT AVG(HocPhi) FROM DangKyKhoaHoc
);

📌 Giải thích: Truy vấn con trong WHERE giúp lọc dữ liệu nâng cao.

5. Truy vấn con trong FROM: Tổng số lượt đăng ký theo chủ đề

SELECT 
    cd.TenChuDe,
    COUNT(dkh.ID) AS TongDangKy
FROM (
    SELECT kh.idChuDe, dkh.ID
    FROM KhoaHoc kh
    JOIN DangKyKhoaHoc dkh ON kh.ID = dkh.idKhoaHoc
) AS Sub
JOIN ChuDe cd ON cd.ID = Sub.idChuDe
GROUP BY cd.TenChuDe;

📌 Giải thích:

  • Truy vấn con trong FROM tách phần trung gian (lượt đăng ký theo idChuDe)

  • Kết hợp với ChuDe để nhóm theo tên chủ đề.

 
 

Luyện tập truy vấn nâng cao với JOIN và Subquery – Ứng dụng quản lý cửa hàng cho thuê xe


1. Mô tả bài toán thực tế

Một cửa hàng cho thuê xe máy cần quản lý:

  • Xe máy: Trạng thái (có sẵn, đang thuê), giá thuê theo giờ.
  • Khách hàng: Ai đang thuê xe, có phải thành viên không.
  • Hợp đồng thuê: Ngày thuê, ngày trả, tổng tiền thuê.

Hệ thống sử dụng các bảng sau:

CREATE TABLE Xe (
    ID INT PRIMARY KEY IDENTITY(1,1),
    BienSo VARCHAR(15) UNIQUE NOT NULL,
    LoaiXe NVARCHAR(100) NOT NULL,
    TrangThai NVARCHAR(50) CHECK (TrangThai IN ('Có sẵn', 'Đang thuê')),
    GiaTheoGio DECIMAL(10,2) NOT NULL
);

CREATE TABLE KhachHang (
    ID INT PRIMARY KEY IDENTITY(1,1),
    HoTen NVARCHAR(100) NOT NULL,
    SoDienThoai VARCHAR(15) UNIQUE NOT NULL,
    LoaiKhachHang NVARCHAR(50) CHECK (LoaiKhachHang IN ('Thành viên', 'Vãng lai'))
);

CREATE TABLE HopDongThue (
    ID INT PRIMARY KEY IDENTITY(1,1),
    IDXe INT FOREIGN KEY REFERENCES Xe(ID),
    IDKhachHang INT FOREIGN KEY REFERENCES KhachHang(ID),
    NgayThue DATETIME NOT NULL,
    NgayTra DATETIME NULL,
    TongTien DECIMAL(10,2) NULL
);

DỮ LIỆU MẪU: 

INSERT INTO Xe (BienSo, LoaiXe, TrangThai, GiaTheoGio) VALUES 
('51A-12345', 'Honda Air Blade', 'Có sẵn', 50000),
('59X-67890', 'Yamaha Exciter', 'Đang thuê', 60000),
('30H-11111', 'Suzuki Raider', 'Có sẵn', 55000),
('79D-22222', 'Honda Vision', 'Đang thuê', 45000),
('43C-33333', 'Yamaha Janus', 'Có sẵn', 40000);
 

INSERT INTO KhachHang (HoTen, SoDienThoai, LoaiKhachHang) VALUES 
('Nguyễn Văn A', '0912345678', 'Thành viên'),
('Trần Thị B', '0987654321', 'Vãng lai'),
('Lê Văn C', '0909123456', 'Thành viên'),
('Phạm Thị D', '0978563412', 'Vãng lai'),
('Hoàng Minh E', '0923456789', 'Thành viên');
 

INSERT INTO HopDongThue (IDXe, IDKhachHang, NgayThue, NgayTra, TongTien) VALUES 
(2, 1, '2024-07-01 08:00:00', '2024-07-01 12:00:00', NULL), -- Đã trả xe, cần tính tiền
(4, 2, '2024-07-02 14:00:00', NULL, NULL), -- Chưa trả xe
(2, 3, '2024-07-03 09:30:00', '2024-07-03 11:30:00', NULL), -- Đã trả xe, cần tính tiền
(1, 4, '2024-07-04 07:00:00', NULL, NULL), -- Chưa trả xe
(5, 5, '2024-07-05 10:00:00', '2024-07-05 13:00:00', NULL); -- Đã trả xe, cần tính tiền
 


2. Các bài tập thực hành

Bài 1: Hiển thị danh sách xe có sẵn để thuê

Bài 2: Danh sách xe đang được thuê kèm thông tin khách hàng

Bài 3: Cập nhật tổng tiền thuê dựa trên thời gian thuê

Bài 4: Tìm khách hàng thuê xe nhiều nhất

Bài 5: Danh sách xe chưa từng được thuê


3. Yêu cầu nộp bài: Gửi file SQL