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