Bài 11: Hàm Xử Lý Chuỗi, Ngày Tháng & Câu Lệnh Nâng Cao
Giai đoạn 3 – Nâng Cao · Mục tiêu: Sử dụng thành thạo các hàm xử lý chuỗi, ngày tháng, và các câu lệnh nâng cao như CASE WHEN, COALESCE, UNION.
1. Hàm xử lý chuỗi (String Functions)
Bảng tổng hợp
| Hàm | Chức năng | Ví dụ | Kết quả |
|---|---|---|---|
CONCAT() | Nối chuỗi | CONCAT('Nguyễn', ' ', 'An') | Nguyễn An |
CONCAT_WS() | Nối với dấu phân cách | CONCAT_WS('-', '2024', '12', '25') | 2024-12-25 |
UPPER() | Chữ HOA | UPPER('hello') | HELLO |
LOWER() | Chữ thường | LOWER('HELLO') | hello |
LENGTH() | Độ dài (bytes) | LENGTH('Xin chào') | 11 |
CHAR_LENGTH() | Độ dài (ký tự) | CHAR_LENGTH('Xin chào') | 8 |
SUBSTRING() | Cắt chuỗi con | SUBSTRING('Hello', 1, 3) | Hel |
LEFT() | Lấy n ký tự bên trái | LEFT('MySQL', 2) | My |
RIGHT() | Lấy n ký tự bên phải | RIGHT('MySQL', 3) | SQL |
TRIM() | Xoá khoảng trắng đầu/cuối | TRIM(' Hi ') | Hi |
REPLACE() | Thay thế chuỗi | REPLACE('2024/12/25', '/', '-') | 2024-12-25 |
REVERSE() | Đảo ngược chuỗi | REVERSE('SQL') | LQS |
LOCATE() | Tìm vị trí chuỗi con | LOCATE('@', 'a@b.com') | 2 |
LPAD() | Đệm trái | LPAD('42', 5, '0') | 00042 |
RPAD() | Đệm phải | RPAD('Hi', 5, '.') | Hi... |
Ví dụ thực tế
-- Hiển thị họ tên viết HOA
SELECT UPPER(HoTen) AS HoTenHoa FROM NhanVien;
-- Tạo mã nhân viên: NV001, NV002, ...
SELECT CONCAT('NV', LPAD(MaNV, 3, '0')) AS MaNhanVien FROM NhanVien;
-- Lấy tên domain từ email
SELECT
Email,
SUBSTRING(Email, LOCATE('@', Email) + 1) AS Domain
FROM KhachHang
WHERE Email IS NOT NULL;
-- Chuẩn hoá số điện thoại (bỏ dấu cách, gạch ngang)
SELECT
DienThoai,
REPLACE(REPLACE(TRIM(DienThoai), '-', ''), ' ', '') AS SDT_Chuan
FROM KhachHang;
-- Viết hoa chữ cái đầu (First Name)
SELECT
CONCAT(UPPER(LEFT(HoTen, 1)), LOWER(SUBSTRING(HoTen, 2))) AS HoTenChuan
FROM NhanVien;
2. Hàm ngày tháng (Date/Time Functions)
Lấy ngày giờ hiện tại
| Hàm | Kết quả | Ví dụ |
|---|---|---|
NOW() | Ngày + Giờ | 2024-12-25 14:30:00 |
CURDATE() | Ngày | 2024-12-25 |
CURTIME() | Giờ | 14:30:00 |
Trích xuất thành phần
| Hàm | Trích xuất | Ví dụ ('2024-12-25') | Kết quả |
|---|---|---|---|
YEAR() | Năm | YEAR('2024-12-25') | 2024 |
MONTH() | Tháng | MONTH('2024-12-25') | 12 |
DAY() | Ngày | DAY('2024-12-25') | 25 |
HOUR() | Giờ | HOUR('14:30:00') | 14 |
DAYNAME() | Tên thứ | DAYNAME('2024-12-25') | Wednesday |
MONTHNAME() | Tên tháng | MONTHNAME('2024-12-25') | December |
DAYOFWEEK() | Thứ (số) | DAYOFWEEK('2024-12-25') | 4 |
QUARTER() | Quý | QUARTER('2024-12-25') | 4 |
Tính toán ngày
-- Thêm 30 ngày
SELECT DATE_ADD('2024-12-25', INTERVAL 30 DAY); -- 2025-01-24
-- Trừ 3 tháng
SELECT DATE_SUB('2024-12-25', INTERVAL 3 MONTH); -- 2024-09-25
-- Khoảng cách giữa 2 ngày
SELECT DATEDIFF('2024-12-31', '2024-01-01'); -- 365
-- Khoảng cách theo tháng
SELECT TIMESTAMPDIFF(MONTH, '2024-01-01', '2024-12-25');-- 11
-- Khoảng cách theo năm
SELECT TIMESTAMPDIFF(YEAR, '2000-05-15', NOW()) AS Tuoi;
Định dạng ngày – DATE_FORMAT
SELECT DATE_FORMAT(NOW(), '%d/%m/%Y') AS 'DD/MM/YYYY'; -- 25/12/2024
SELECT DATE_FORMAT(NOW(), '%d-%m-%Y %H:%i') AS 'Ngày giờ'; -- 25-12-2024 14:30
SELECT DATE_FORMAT(NOW(), '%W, %d %M %Y') AS 'Đầy đủ'; -- Wednesday, 25 December 2024
| Ký hiệu | Ý nghĩa | Ví dụ |
|---|---|---|
%Y | Năm (4 số) | 2024 |
%m | Tháng (2 số) | 12 |
%d | Ngày (2 số) | 25 |
%H | Giờ (24h) | 14 |
%i | Phút | 30 |
%s | Giây | 00 |
%W | Tên thứ | Wednesday |
%M | Tên tháng | December |
Ví dụ thực tế
-- Nhân viên đã làm việc bao nhiêu năm
SELECT
HoTen,
NgayVaoLam,
TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) AS SoNamLamViec
FROM NhanVien;
-- Đơn hàng trong 7 ngày gần đây
SELECT * FROM DonHang
WHERE NgayDat >= DATE_SUB(CURDATE(), INTERVAL 7 DAY);
-- Thống kê đơn hàng theo quý
SELECT
QUARTER(NgayDat) AS Quy,
COUNT(*) AS SoDon,
SUM(TongTien) AS DoanhThu
FROM DonHang
WHERE YEAR(NgayDat) = 2024
GROUP BY QUARTER(NgayDat);
3. CASE WHEN – Biểu thức điều kiện
Cú pháp
CASE
WHEN dieu_kien_1 THEN gia_tri_1
WHEN dieu_kien_2 THEN gia_tri_2
ELSE gia_tri_mac_dinh
END
Ví dụ
-- Phân loại sản phẩm theo giá
SELECT
TenSP,
Gia,
CASE
WHEN Gia >= 30000000 THEN 'Cao cấp'
WHEN Gia >= 15000000 THEN 'Trung cấp'
WHEN Gia >= 5000000 THEN 'Phổ thông'
ELSE 'Giá rẻ'
END AS PhanLoai
FROM SanPham;
-- Phân loại nhân viên theo thâm niên
SELECT
HoTen,
NgayVaoLam,
TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) AS SoNam,
CASE
WHEN TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) >= 5 THEN ' Kỳ cựu'
WHEN TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) >= 2 THEN ' Có kinh nghiệm'
ELSE ' Mới'
END AS ThamNien
FROM NhanVien;
-- Đếm số lượng theo phân loại
SELECT
CASE
WHEN Luong >= 25000000 THEN 'Cao'
WHEN Luong >= 15000000 THEN 'Trung bình'
ELSE 'Thấp'
END AS MucLuong,
COUNT(*) AS SoNV
FROM NhanVien
GROUP BY MucLuong;
CASE WHEN trong UPDATE
-- Tăng lương theo thâm niên
UPDATE NhanVien
SET Luong = Luong * CASE
WHEN TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) >= 5 THEN 1.15
WHEN TIMESTAMPDIFF(YEAR, NgayVaoLam, CURDATE()) >= 2 THEN 1.10
ELSE 1.05
END;
4. COALESCE & IFNULL – Xử lý NULL
IFNULL – Thay thế NULL
-- Nếu Email là NULL → hiển thị "Chưa có"
SELECT HoTen, IFNULL(Email, 'Chưa cập nhật') AS Email
FROM KhachHang;
COALESCE – Chọn giá trị đầu tiên khác NULL
-- Ưu tiên: Email → SĐT → "Không có thông tin"
SELECT
HoTen,
COALESCE(Email, DienThoai, 'Không có thông tin liên hệ') AS LienHe
FROM KhachHang;
5. UNION – Gộp kết quả nhiều truy vấn
UNION (loại bỏ trùng)
-- Gộp tên khách hàng và tên nhân viên
SELECT HoTen, 'Khách hàng' AS Loai FROM KhachHang
UNION
SELECT HoTen, 'Nhân viên' AS Loai FROM NhanVien;
UNION ALL (giữ trùng)
-- Gộp mà KHÔNG loại bỏ trùng (nhanh hơn)
SELECT HoTen FROM KhachHang
UNION ALL
SELECT HoTen FROM NhanVien;
:::info Quy tắc UNION
- Số cột ở mỗi SELECT phải bằng nhau.
- Kiểu dữ liệu các cột tương ứng phải tương thích.
- Tên cột lấy từ SELECT đầu tiên. :::
Ví dụ thực tế
-- Báo cáo doanh thu Q3 và Q4 trên cùng 1 bảng
SELECT 'Q3' AS Quy, SUM(TongTien) AS DoanhThu FROM DonHang
WHERE NgayDat BETWEEN '2024-07-01' AND '2024-09-30'
UNION ALL
SELECT 'Q4', SUM(TongTien) FROM DonHang
WHERE NgayDat BETWEEN '2024-10-01' AND '2024-12-31';
6. Hàm toán học bổ sung
| Hàm | Chức năng | Ví dụ | Kết quả |
|---|---|---|---|
ABS() | Giá trị tuyệt đối | ABS(-5) | 5 |
ROUND() | Làm tròn | ROUND(3.456, 2) | 3.46 |
CEIL() | Làm tròn lên | CEIL(3.1) | 4 |
FLOOR() | Làm tròn xuống | FLOOR(3.9) | 3 |
MOD() | Chia lấy dư | MOD(10, 3) | 1 |
POW() | Luỹ thừa | POW(2, 3) | 8 |
SQRT() | Căn bậc 2 | SQRT(16) | 4 |
RAND() | Số ngẫu nhiên | RAND() | 0.xxxxx |
-- Lấy 5 sản phẩm ngẫu nhiên
SELECT TenSP, Gia FROM SanPham ORDER BY RAND() LIMIT 5;
-- Tính phần trăm doanh thu từng sản phẩm
SELECT
TenSP,
SUM(TongTien) AS DoanhThu,
ROUND(SUM(TongTien) / (SELECT SUM(TongTien) FROM DonHang) * 100, 2) AS PhanTram
FROM DonHang
GROUP BY TenSP
ORDER BY DoanhThu DESC;
Bài tập thực hành
Bài 1: Hàm chuỗi
- Hiển thị họ tên nhân viên dạng CHỮ HOA.
- Tạo mã nhân viên dạng:
NV-001,NV-002, ... - Lấy phần họ (từ đầu tiên) từ cột HoTen.
- Đếm số ký tự trong tên mỗi nhân viên.
- Thay thế tất cả
@company.comthành@newcompany.comtrong cột Email.
Bài 2: Hàm ngày
- Hiển thị nhân viên kèm số năm làm việc.
- Tìm nhân viên có sinh nhật trong tháng này.
- Thống kê đơn hàng theo tháng/năm, hiển thị định dạng
"Tháng 12/2024". - Tìm đơn hàng trong 30 ngày gần đây.
Bài 3: CASE WHEN
- Phân loại nhân viên: Lương ≥ 25tr → "Cao", ≥ 15tr → "TB", còn lại → "Thấp".
- Hiển thị trạng thái đơn hàng bằng emoji: Chờ xác nhận → , Đang giao → , Hoàn thành → , Đã huỷ → .
- Đếm số nhân viên ở mỗi mức lương.
Bài 4: Tổng hợp
- Hiển thị nhân viên kèm: mã NV (NV-001), tuổi, thâm niên, mức lương, liên hệ (email hoặc SĐT).
- Thống kê: mỗi phòng ban có bao nhiêu nhân viên mức lương Cao/TB/Thấp.
Quay lại: Roadmap · Bài tiếp: Bài 12 – Dự Án Tổng Hợp