Để làm việc hiệu quả với hệ quản trị cơ sở dữ liệu, người lập trình cần nắm vững các cú pháp từ khởi tạo bảng, thao tác dữ liệu đến truy vấn phức tạp. Các ví dụ dưới đây minh họa cách xử lý dữ liệu thực tế, bao gồm lọc ngày tháng, tính toán tổng hợp và kết nối nhiều bảng.
1. Lọc dữ liệu theo thời gian và mẫu chuỗi
Trước tiên, chúng ta sẽ thiết lập bảng nguoi_dung (users) và thêm một vài bản ghi dữ liệu giả lập:
-- Khởi tạo bảng người dùng
CREATE TABLE nguoi_dung (
ma_nguoi_dung INT PRIMARY KEY,
ho_va_ten VARCHAR(100),
dia_chi_email VARCHAR(100),
mat_khau VARCHAR(255),
thoi_gian_dang_ky TIMESTAMP
);
-- Thêm dữ liệu mẫu
INSERT INTO nguoi_dung (ma_nguoi_dung, ho_va_ten, dia_chi_email, mat_khau, thoi_gian_dang_ky)
VALUES (101, 'Nguyen Van A', 'nguyena@vidu.com', 'hashed_pass_1', '2023-05-10 08:30:00');
INSERT INTO nguoi_dung (ma_nguoi_dung, ho_va_ten, dia_chi_email, mat_khau, thoi_gian_dang_ky)
VALUES (102, 'Tran Thi B', 'tranthib@vidu.com', 'hashed_pass_2', '2023-06-15 09:00:00');
Sau khi có dữ liệu, ta có thể sử dụng câu lệnh SELECT kết hợp với mệnh đề WHERE để tìm kiếm các bản ghi thỏa mãn điều kiện về thời gian và định dạng email. Hàm DATE_SUB và NOW() giúp tính toán thời gian linh hoạt.
-- Truy vấn người dùng đăng ký cách đây hơn 7 ngày và có đuôi email '@vidu.com'
SELECT *
FROM nguoi_dung
WHERE thoi_gian_dang_ky < DATE_SUB(NOW(), INTERVAL 7 DAY)
AND dia_chi_email LIKE '%@vidu.com';
2. Kết nối bảng và tính toán tổng hợp (Aggregation)
Trong các hệ thống bán hàng, dữ liệu thường được phân chia thành các bảng riêng biệt như sản phẩm và đơn hàng. Để tính toán doanh thu hoặc số lượng bán ra, ta cần sử dụng JOIN để kết nối dữ liệu và GROUP BY để nhóm kết quả.
-- Bảng thông tin sản phẩm
CREATE TABLE san_pham (
id_sp INT PRIMARY KEY,
ten_san_pham VARCHAR(150),
gia_ban DECIMAL(12, 2)
);
-- Bảng chi tiết đơn hàng
CREATE TABLE chi_tiet_don_hang (
id_don INT PRIMARY KEY,
ten_khach VARCHAR(100),
ngay_mua DATE,
ma_sp INT,
so_luong INT,
FOREIGN KEY (ma_sp) REFERENCES san_pham(id_sp)
);
-- Nhập liệu
INSERT INTO san_pham VALUES
(1, 'Laptop Gaming', 1500.00),
(2, 'Chuột không dây', 25.50),
(3, 'Bàn phím cơ', 80.00);
INSERT INTO chi_tiet_don_hang VALUES
(501, 'Le Van C', '2023-08-01', 1, 1),
(502, 'Pham Thi D', '2023-08-02', 2, 5),
(503, 'Hoang Van E', '2023-08-03', 3, 2);
Câu lệnh dưới đây sẽ hiển thị tổng số lượng đã bán của từng sản phẩm bằng cách ghép bảng san_pham và chi_tiet_don_hang dựa trên khóa ngoại.
-- Tính tổng số lượng bán ra theo tên sản phẩm
SELECT sp.ten_san_pham, SUM(dh.so_luong) AS tong_ban_ra
FROM san_pham sp
JOIN chi_tiet_don_hang dh ON sp.id_sp = dh.ma_sp
GROUP BY sp.ten_san_pham;
3. Bộ lọc nhóm dữ liệu (HAVING)
Mệnh đề WHERE không thể dùng để lọc các hàm tổng hợp như SUM hay COUNT. Thay vào đó, ta sử dụng HAVING sau mệnh đề GROUP BY.
-- Tạo bảng giao dịch tài chính
CREATE TABLE giao_dich (
giao_dich_id INT PRIMARY KEY,
ma_khachhang INT,
ngay_gd DATE,
so_tien DECIMAL(15, 2)
);
INSERT INTO giao_dich VALUES
(1, 900, '2023-09-01', 1200.50),
(2, 901, '2023-09-02', 300.00),
(3, 900, '2023-09-05', 500.00);
Để tìm ra những khách hàng có tổng giao dịch vượt quá một ngưỡng nhất định (ví dụ: 1000), ta viết câu truy vấn như sau:
-- Tìm khách hàng có tổng số tiền giao dịch lớn hơn 1000
SELECT ma_khachhang, SUM(so_tien) AS tong_tien_gd
FROM giao_dich
GROUP BY ma_khachhang
HAVING SUM(so_tien) > 1000;
4. Truy vấn khoảng ngày (Date Range)
Khi làm việc với cột thời gian, SQL cung cấp toán tử BETWEEN để xác định một phạm vi giá trị.
-- Lấy danh sách người dùng đăng ký trong khoảng thời gian cụ thể
SELECT *
FROM nguoi_dung
WHERE thoi_gian_dang_ky BETWEEN '2023-01-01 00:00:00' AND '2023-12-31 23:59:59';
-- Hoặc tìm người đăng ký trước 7 ngày so với hiện tại
SELECT *
FROM nguoi_dung
WHERE thoi_gian_dang_ky < DATE_SUB(NOW(), INTERVAL 7 DAY);
5. Hàm tính giá trị trung bình (AVG)
Ngoài phép cộng tổng SUM, ta thường cần tính giá trị trung bình của một trường số liệu.
-- Tính giá trung bình của các sản phẩm đã bán
SELECT sp.ten_san_pham, AVG(sp.gia_ban) AS gia_trung_binh
FROM san_pham sp
JOIN chi_tiet_don_hang dh ON sp.id_sp = dh.ma_sp
GROUP BY sp.ten_san_pham;
6. Kết hợp điều kiện logic (AND, OR, NOT)
Việc kết hợp các điều kiện logic giúp truy vấn chính xác hơn. Lưu ý rằng trong ví dụ gốc, bảng nguoi_dung không có cột tuổi, nên chúng ta sẽ thêm cột tuoi vào bảng để câu lệnh hoạt động đúng.
-- Điều chỉnh bảng thêm cột tuổi (giả định)
ALTER TABLE nguoi_dung ADD COLUMN tuoi INT;
-- Cập nhật dữ liệu tuổi
UPDATE nguoi_dung SET tuoi = 22 WHERE ma_nguoi_dung = 101;
UPDATE nguoi_dung SET tuoi = 28 WHERE ma_nguoi_dung = 102;
Tiến hành truy vấn với các điều kiện phức tạp:
-- Tìm người dùng lớn hơn 25 tuổi và tên bắt đầu bằng chữ 'N'
SELECT *
FROM nguoi_dung
WHERE tuoi > 25
AND ho_va_ten LIKE 'N%';
-- Tìm người có tên là 'Nguyen Van A' hoặc email chứa 'vidu'
SELECT *
FROM nguoi_dung
WHERE ho_va_ten = 'Nguyen Van A'
OR dia_chi_email LIKE '%vidu%';
-- Loại trừ người dùng có tên cụ thể và email cụ thể
SELECT *
FROM nguoi_dung
WHERE NOT (ho_va_ten = 'Nguyen Van A' AND dia_chi_email = 'nguyena@vidu.com');
7. Tính toán doanh thu tổng (Total Revenue)
Để tính tổng doanh thu, ta cần nhân số lượng (quantity) với đơn giá (price) ngay trong câu lệnh SELECT hoặc SUM.
-- Tính doanh thu theo từng sản phẩm
SELECT sp.ten_san_pham,
SUM(dh.so_luong) AS sl_ban,
SUM(dh.so_luong * sp.gia_ban) AS doanh_thu
FROM san_pham sp
JOIN chi_tiet_don_hang dh ON sp.id_sp = dh.ma_sp
GROUP BY sp.ten_san_pham;
8. Sắp xếp, giới hạn và cập nhật dữ liệu
Cuối cùng, các thao tác quản trị dữ liệu bao gồm sắp xếp (ORDER BY), giới hạn số kết quả (LIMIT), sửa (UPDATE) và xóa (DELETE).
-- Bảng dữ liệu nhân sự
CREATE TABLE nhan_vien (
nv_id INT PRIMARY KEY,
ten_nhan_vien VARCHAR(100),
luong_thang DECIMAL(10, 2),
phong_ban VARCHAR(50)
);
INSERT INTO nhan_vien VALUES
(1, 'Le Minh', 1000.00, 'IT'),
(2, 'Hoang Lan', 1200.00, 'HR'),
(3, 'Vu Tien', 900.00, 'IT'),
(4, 'Phuong Thao', 1500.00, 'Sales');
-- Lấy nhân viên có lương cao nhất
SELECT *
FROM nhan_vien
ORDER BY luong_thang DESC
LIMIT 1;
-- Tăng lương cho nhân viên mã 1
UPDATE nhan_vien
SET luong_thang = 1100.00
WHERE nv_id = 1;
-- Xóa nhân viên nghỉ việc
DELETE FROM nhan_vien
WHERE nv_id = 4;