Chuyển tới nội dung chính

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àmChức năngVí dụKết quả
CONCAT()Nối chuỗiCONCAT('Nguyễn', ' ', 'An')Nguyễn An
CONCAT_WS()Nối với dấu phân cáchCONCAT_WS('-', '2024', '12', '25')2024-12-25
UPPER()Chữ HOAUPPER('hello')HELLO
LOWER()Chữ thườngLOWER('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 conSUBSTRING('Hello', 1, 3)Hel
LEFT()Lấy n ký tự bên tráiLEFT('MySQL', 2)My
RIGHT()Lấy n ký tự bên phảiRIGHT('MySQL', 3)SQL
TRIM()Xoá khoảng trắng đầu/cuốiTRIM(' Hi ')Hi
REPLACE()Thay thế chuỗiREPLACE('2024/12/25', '/', '-')2024-12-25
REVERSE()Đảo ngược chuỗiREVERSE('SQL')LQS
LOCATE()Tìm vị trí chuỗi conLOCATE('@', 'a@b.com')2
LPAD()Đệm tráiLPAD('42', 5, '0')00042
RPAD()Đệm phảiRPAD('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àmKết quảVí dụ
NOW()Ngày + Giờ2024-12-25 14:30:00
CURDATE()Ngày2024-12-25
CURTIME()Giờ14:30:00

Trích xuất thành phần​

HàmTrích xuấtVí dụ ('2024-12-25')Kết quả
YEAR()NămYEAR('2024-12-25')2024
MONTH()ThángMONTH('2024-12-25')12
DAY()NgàyDAY('2024-12-25')25
HOUR()GiờHOUR('14:30:00')14
DAYNAME()Tên thứDAYNAME('2024-12-25')Wednesday
MONTHNAME()Tên thángMONTHNAME('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ĩaVí dụ
%YNăm (4 số)2024
%mTháng (2 số)12
%dNgày (2 số)25
%HGiờ (24h)14
%iPhút30
%sGiây00
%WTên thứWednesday
%MTên thángDecember

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àmChức năngVí dụKết quả
ABS()Giá trị tuyệt đốiABS(-5)5
ROUND()Làm trònROUND(3.456, 2)3.46
CEIL()Làm tròn lênCEIL(3.1)4
FLOOR()Làm tròn xuốngFLOOR(3.9)3
MOD()Chia lấy dưMOD(10, 3)1
POW()Luỹ thừaPOW(2, 3)8
SQRT()Căn bậc 2SQRT(16)4
RAND()Số ngẫu nhiênRAND()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​

  1. Hiển thị họ tên nhân viên dạng CHỮ HOA.
  2. Tạo mã nhân viên dạng: NV-001, NV-002, ...
  3. Lấy phần họ (từ đầu tiên) từ cột HoTen.
  4. Đếm số ký tự trong tên mỗi nhân viên.
  5. Thay thế tất cả @company.com thành @newcompany.com trong cột Email.

Bài 2: Hàm ngày​

  1. Hiển thị nhân viên kèm số năm làm việc.
  2. Tìm nhân viên có sinh nhật trong tháng này.
  3. Thống kê đơn hàng theo tháng/năm, hiển thị định dạng "Tháng 12/2024".
  4. Tìm đơn hàng trong 30 ngày gần đây.

Bài 3: CASE WHEN​

  1. Phân loại nhân viên: Lương ≥ 25tr → "Cao", ≥ 15tr → "TB", còn lại → "Thấp".
  2. 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ỷ → .
  3. Đếm số nhân viên ở mỗi mức lương.

Bài 4: Tổng hợp​

  1. 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).
  2. 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