Messy Customer Names: Cleaning Them With Five String Functions

Beginner 4 min read Updated 30 Jul 2026 UPA AI Partner

Three rows, one person: “nguyen an”, “Nguyen An ” and “NGUYEN AN”. Your COUNT DISTINCT is reporting three customers.

The problem

The full_name column is hand-typed across three source systems. The same person shows up three ways, and every count is wrong.

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

Five functions cover 90% of cases

FunctionDoesExample
TRIMStrip surrounding spacesTRIM(' an ')'an'
UPPER / LOWERNormalise caseLOWER('AN')'an'
CONCATJoin stringsCONCAT(first,' ',last)
SUBSTRINGTake a sliceSUBSTRING(code,1,3)
REPLACESwap charactersREPLACE(phone,'-','')
SELECT
  INITCAP(LOWER(TRIM(full_name))) AS clean_name,
  COUNT(*)
FROM customers
GROUP BY 1;

Common mistakes

1. CONCAT meets NULL

-- MySQL: the whole string becomes NULL if middle_name is NULL
SELECT CONCAT(first, ' ', middle_name, ' ', last) FROM customers;

-- Safe
SELECT CONCAT_WS(' ', first, middle_name, last) FROM customers;

CONCAT_WS skips NULL automatically. In PostgreSQL the || operator also nullifies the whole string — guard it with COALESCE(middle_name,'').

2. Positions start at 1, not 0

SUBSTRING('ABCDEF', 1, 3)   -- 'ABC'
SUBSTRING('ABCDEF', 0, 3)   -- 'AB'  (easy to trip over)

3. Cleaning inside WHERE kills the index

-- Full table scan
WHERE LOWER(TRIM(email)) = 'an@gmail.com'

If you filter this way regularly, clean the data once at load time, or add a normalised column with its own index.

4. Multi-byte characters

In some engines LENGTH returns bytes, not characters. In UTF-8, “Nguyễn” is 6 characters but 8 bytes. Use CHAR_LENGTH when you mean characters.

Splitting a string into columns

-- Extract the email domain
SELECT SPLIT_PART(email, '@', 2) AS domain     -- PostgreSQL
SELECT SUBSTRING_INDEX(email, '@', -1)         -- MySQL
FROM users;

Practice

  • 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 and rounding)
  • HackerRank — Name of Employees

Key takeaways

  • TRIM plus LOWER resolves most hand-entry duplicates.
  • CONCAT with a NULL nullifies everything — use CONCAT_WS.
  • SUBSTRING positions are 1-based.
  • Cleaning inside WHERE discards the index; clean at load time.
  • For accented text use CHAR_LENGTH, not LENGTH.

You have just learned hàm xử lý chuỗi

Ready to practise?

Work through hàm xử lý chuỗi exercises on real data, graded the moment you hit run.

Start practising →