Dữ liệu tên khách hàng bẩn: làm sạch bằng 5 hàm chuỗi

Cơ bản 5 phút đọc Cập nhật 30/07/2026 UPA AI Partner

Ba dòng cùng là một người: “nguyen an”, “Nguyen An ” và “NGUYEN AN”. COUNT DISTINCT của bạn đang đếm ba khách.

Bài toán

Cột ho_ten nhập tay từ ba nguồn khác nhau. Cùng một người xuất hiện ba kiểu, và mọi phép đếm đều sai.

DỮ LIỆU THÔho_ten nguyỄN an trần BÌNHLÊ chiBƯỚC 1sau TRIMnguyỄN antrần BÌNHLÊ chiBƯỚC 2chuẩn hoáNguyễn AnTrần BìnhLê ChiTRIMINITCAP

Năm hàm giải quyết 90% trường hợp

HàmViệcVí dụ
TRIMCắt khoảng trắng hai đầuTRIM(' an ')'an'
UPPER / LOWERChuẩn hoá hoa thườngLOWER('AN')'an'
CONCATGhép chuỗiCONCAT(ho,' ',ten)
SUBSTRINGCắt một đoạnSUBSTRING(ma,1,3)
REPLACEThay thếREPLACE(sdt,'-','')
SELECT
  INITCAP(LOWER(TRIM(ho_ten))) AS ho_ten_sach,
  COUNT(*)
FROM khach_hang
GROUP BY 1;

Lỗi thường gặp

1. CONCAT gặp NULL

-- MySQL: cả chuỗi thành NULL nếu ten_dem là NULL
SELECT CONCAT(ho, ' ', ten_dem, ' ', ten) FROM khach_hang;

-- An toàn
SELECT CONCAT_WS(' ', ho, ten_dem, ten) FROM khach_hang;

CONCAT_WS tự bỏ qua NULL. Trên PostgreSQL, toán tử || cũng biến cả chuỗi thành NULL — dùng COALESCE(ten_dem,'') để chặn.

2. Vị trí bắt đầu từ 1, không phải 0

SUBSTRING('ABCDEF', 1, 3)   -- 'ABC'
SUBSTRING('ABCDEF', 0, 3)   -- 'AB'  (dễ nhầm)

3. Làm sạch trong WHERE là mất chỉ mục

-- Quét toàn bảng
WHERE LOWER(TRIM(email)) = 'an@gmail.com'

Nếu phải lọc thường xuyên như vậy, hãy làm sạch dữ liệu một lần khi nạp, hoặc tạo cột đã chuẩn hoá kèm chỉ mục riêng.

4. Cắt chuỗi có dấu tiếng Việt

LENGTH ở một số hệ trả về số byte, không phải số ký tự. Với UTF-8, “Nguyễn” có 6 ký tự nhưng 8 byte. Dùng CHAR_LENGTH khi bạn muốn đếm ký tự.

Tách chuỗi thành cột

-- Lấy tên miền từ email
SELECT SPLIT_PART(email, '@', 2) AS ten_mien   -- PostgreSQL
SELECT SUBSTRING_INDEX(email, '@', -1)         -- MySQL
FROM nguoi_dung;

Luyện tập

  • LeetCode 1667 — Fix Names in a Table
  • LeetCode 1484 — Group Sold Products By The Date
  • LeetCode 1965 — Employees With Missing Information
  • HackerRank — The Blunder (REPLACE và làm tròn)
  • HackerRank — Name of Employees

Tóm lại

  • TRIM + LOWER giải quyết phần lớn dữ liệu trùng do nhập tay.
  • CONCAT gặp NULL làm hỏng cả chuỗi — dùng CONCAT_WS.
  • Vị trí trong SUBSTRING đếm từ 1.
  • Làm sạch trong WHERE là mất chỉ mục; hãy làm sạch khi nạp dữ liệu.
  • Tiếng Việt có dấu: dùng CHAR_LENGTH, không dùng LENGTH.

Bạn vừa học xong hàm xử lý chuỗi

Sẵn sàng luyện tập chưa?

Làm bài tập hàm xử lý chuỗi trên dữ liệu thật, chấm điểm ngay khi bạn bấm chạy.

Bắt đầu luyện tập →