Học bằng cách đọc theo thứ tự

Hàm ② — Hàm chuỗi (LENGTH / TRIM / REPLACE / UPPER / SUBSTR)

Bài thứ hai trong ba bài về hàm SQL. Bao gồm LENGTH để đếm ký tự, TRIM để cắt khoảng trắng, REPLACE để thay thế, UPPER / LOWER để chuyển chữ hoa-thường, và SUBSTR — tất cả trên tập dữ liệu staff được tải từ CSV.

Dữ liệu dùng trong bài này — bảng staff

Bài thứ hai về hàm tập trung vào hàm chuỗi. Chúng ta sẽ đi qua các hàm bạn sẽ dùng bất cứ khi nào cần làm sạch hoặc biến đổi văn bản lấy từ bảng đang hoạt động: độ dài, cắt khoảng trắng, thay thế, chuyển đổi chữ hoa-thường, và trích xuất chuỗi con.

Tập dữ liệu vẫn là bảng staff như lần trước (10 hàng: name / city / salary, v.v.). Lấy các tên trong cột name làm ngôi sao, bốn bài thực hành bao gồm tính độ dài, thay thế họ, viết hoa, và trích xuất chữ cái đầu.

Trước khi bắt đầu các bài thực hành, hãy kiểm tra định nghĩa cộtdữ liệu mẫu của bảng staff.

① Chạy PRAGMA table_info(staff); để xem tên cột, kiểu và khóa chính.

② Chạy SELECT * FROM staff LIMIT 5; để xem trước 5 hàng đầu.

SQL Editor

Chạy truy vấn để xem kết quả

Độ dài chuỗi — `LENGTH` và `CHAR_LENGTH`

Hàm đo độ dài chuỗi hoạt động khác nhau giữa console của khóa học này (SQLite) và MySQL, nên hãy chú ý:

- Console khóa học này (SQLite): LENGTH(s) trả về số ký tự ('phở' → 3)

- MySQL: LENGTH(s) trả về số byte ('phở' → 5, vì chiếm 3 byte trong UTF-8). Để lấy số ký tự, dùng CHAR_LENGTH(s)

Bài này dùng LENGTH() cho các bài thực hành, nhưng việc biết sự khác biệt là quan trọng — văn bản tiếng Việt có dấu thanh điệu hầu như luôn là chuỗi đa byte.

Sự khác biệt giữa `LENGTH` và `CHAR_LENGTH`
Đầu vàoSQLiteLENGTHMySQLLENGTH (byte)MySQLCHAR_LENGTH'ABC'3 (ký tự)3 (byte)3 (ký tự)'phở'3 (ký tự)5 (byte)ở chiếm 3 byte UTF-83 (ký tự)'Alice'555
Console của khóa học này (SQLite) trả về số ký tự với LENGTH. MySQL trả về số byte với LENGTH, và số ký tự với CHAR_LENGTH. Khoảng cách rõ nhất với ký tự đa byte như tiếng Nhật.
-- 1) Đếm ký tự (trong console của khóa học này, LENGTH trả về số ký tự)
SELECT LENGTH('Alice');         -- 5
SELECT LENGTH('phở');           -- 3 (ở đây), 5 (LENGTH của MySQL = số byte)

-- 2) Sắp xếp theo độ dài cột
SELECT name, LENGTH(name) AS name_len FROM staff
ORDER BY name_len DESC;

-- Tham khảo: trong MySQL, số ký tự là CHAR_LENGTH(s)
--   SELECT CHAR_LENGTH('phở') FROM dual;  -- 3

Hãy tưởng tượng một danh sách nhân viên làm nổi bật «TOP 3 nhân viên theo độ dài tên đầy đủ». (Nếu bạn chạy đúng, một giải thích sẽ hiện ra.)

① Từ bảng staff, lấy name`LENGTH(name)` với bí danh `name_len` — tổng 2 cột.

② Sắp xếp theo name_len giảm dần. Trường hợp bằng nhau, phá vỡ bằng name tăng dần (thứ tự bảng chữ cái) — sắp xếp đa cấp.

③ Giới hạn ở 3 hàng đầu.

④ Kiểm tra kết quả là 3 hàng: Iris Watanabe 13 / Alice Tanaka 12 / Carol Tanaka 12.

SQL Editor

Chạy truy vấn để xem kết quả

Cắt khoảng trắng và thay thế — `TRIM` và `REPLACE`

Trong các bảng thực tế, bạn sẽ gặp khoảng trắng không mong muốn — «ai đó sao chép-dán với khoảng trắng thừa đầu/cuối», «hệ thống trước khi di chuyển để lại khoảng trắng full-width bên trong dữ liệu», v.v. `TRIM(s)` cắt khoảng trắng ở cả hai đầu chuỗi; LTRIM(s) chỉ cắt bên trái, và RTRIM(s) chỉ cắt bên phải.

`REPLACE(s, tìm, thay)` thay thế mọi xuất hiện của tìm trong s bằng thay. Đây là hàm chủ lực cho chuẩn hóa và di chuyển — «viết tắt họ phổ biến Tanaka thành T. để hiển thị gọn», «đổi phần domain của email sang domain mới», v.v. Kết hợp với UPDATE và bạn có thể viết lại giá trị trực tiếp trong bảng.

-- 1) Cắt khoảng trắng: TRIM / LTRIM / RTRIM
SELECT TRIM('  Hello  ');     -- 'Hello'
SELECT LTRIM('  Hello  ');    -- 'Hello  '
SELECT RTRIM('  Hello  ');    -- '  Hello'

-- TRIM trên cột: phát hiện hàng có khoảng trắng bằng chênh lệch độ dài
SELECT name FROM staff
WHERE LENGTH(name) <> LENGTH(TRIM(name));

-- 2) Thay thế: REPLACE
SELECT REPLACE('I LIKE APPLE', 'APPLE', 'BANANA');
-- 'I LIKE BANANA'

-- REPLACE trên cột — viết tắt 'Tanaka' thành 'T.'
SELECT name, REPLACE(name, 'Tanaka', 'T.') AS short_name
FROM staff;

Áp dụng TRIM — kết hợp với UPDATE để sửa văn bản không nhất quán

TRIM không chỉ để đọc — kết hợp với UPDATE, nó có thể viết lại giá trị trực tiếp trong bảng. Ví dụ, để chuẩn hóa hàng loạt cột name có khoảng trắng đầu/cuối thừa, viết kiểu UPDATE staff SET name = TRIM(name) WHERE LENGTH(name) <> LENGTH(TRIM(name)); — mẫu an toàn là lọc trước bằng WHERE, rồi UPDATE. Nếu bỏ WHERE, mỗi hàng đều bị TRIM (gần như vô hại nhưng UPDATE thừa). REPLACE hoạt động tương tự: UPDATE bảng SET cột = REPLACE(cột, 'A', 'B') là kỹ thuật cơ bản để sửa hàng loạt văn bản không nhất quán.

Hãy tưởng tượng một yêu cầu: «trên dashboard hiển thị gọn, viết tắt họ phổ biến Tanaka thành T.».

① Từ bảng staff, lấy name`REPLACE(name, 'Tanaka', 'T.')` với bí danh `short_name` — tổng 2 cột.

② Kiểm tra kết quả có 10 hàng. 4 cái tên chứa Tanaka (Alice / Carol / Frank / Jack) phải có short_name như 'Alice T.' / 'Carol T.'.

SQL Editor

Chạy truy vấn để xem kết quả

Chuyển đổi chữ hoa-thường và chuỗi con — `UPPER` / `LOWER` / `SUBSTR`

`UPPER(s)` chuyển chuỗi thành tất cả chữ hoa, và `LOWER(s)` thành tất cả chữ thường. Dùng chúng khi bạn muốn điều kiện tìm kiếm không phân biệt chữ hoa-thường (WHERE UPPER(email) = 'X@Y.COM') hoặc định dạng hiển thị nhất quán. Chúng không tác động đến các ký tự không có phân biệt chữ hoa-thường (như tiếng Nhật).

`SUBSTR(s, bắt_đầu, độ_dài)` trích xuất `độ_dài` ký tự bắt đầu từ vị trí `bắt_đầu` (bạn cũng có thể viết là SUBSTRING). Vị trí trong SQL bắt đầu từ 1, nên SUBSTR('Alice Tanaka', 1, 5) trả về 'Alice'. Bỏ đối số thứ ba và nó trả về tất cả đến cuối; truyền bắt_đầu âm như SUBSTR(s, -3) và nó đếm từ cuối.

UPPER / LOWER / SUBSTR nhìn lướt
HàmVí dụ gọiKết quảUPPERUPPER('Alice')'ALICE'LOWERLOWER('ALICE')'alice'SUBSTRSUBSTR('Alice Tanaka', 1, 5)'Alice'
UPPER và LOWER nhận một đối số và đổi chữ hoa-thường của toàn chuỗi. SUBSTR nhận 3 đối số — (đích, bắt đầu, độ dài) — và vị trí bắt đầu là cơ số 1.
-- 1) UPPER / LOWER
SELECT UPPER('apple'), LOWER('APPLE');
-- 'APPLE', 'apple'

-- Trên cột: lấy tên ở dạng chữ hoa và chữ thường
SELECT name, UPPER(name) AS upper_name, LOWER(name) AS lower_name
FROM staff;

-- 2) SUBSTR: vị trí là cơ số 1
SELECT SUBSTR('Alice Tanaka', 1, 5);   -- 'Alice'
SELECT SUBSTR('Alice Tanaka', 7, 6);   -- 'Tanaka'
SELECT SUBSTR('Alice Tanaka', 7);      -- 'Tanaka'  -- bỏ độ dài → đến cuối
SELECT SUBSTR('Alice Tanaka', -6);     -- 'Tanaka'  -- âm → từ cuối

-- Ký tự đầu tiên của mỗi tên
SELECT name, SUBSTR(name, 1, 1) AS initial FROM staff;

-- Tham khảo: REVERSE là hàm MySQL / Oracle — không có trong console của khóa học này
--   SELECT REVERSE('Alice Tanaka');  -- 'akanaT ecilA' (hoạt động trong MySQL)

Hãy tưởng tượng một yêu cầu: «nhóm các file nhân viên theo chữ cái đầu, vì vậy trích xuất từng chữ cái đầu và sắp xếp».

① Từ bảng staff, lấy name, `UPPER(name)` như `upper_name`, và `SUBSTR(name, 1, 1)` như `initial` — tổng 3 cột.

② Sắp xếp theo initial tăng dần (thứ tự bảng chữ cái), với name tăng dần là tiêu chí phá vỡ khi bằng.

③ Kiểm tra kết quả có 10 hàng, bắt đầu với Alice Tanaka / ALICE TANAKA / A và kết thúc với Jack Tanaka / JACK TANAKA / J.

SQL Editor

Chạy truy vấn để xem kết quả

Tìm vị trí của chuỗi con — `INSTR`

`INSTR(đích, tìm)` trả về vị trí (chỉ số cơ số 1) nơi `tìm` xuất hiện đầu tiên trong đích. Vị trí bắt đầu từ 1, và nếu chuỗi tìm kiếm không thấy, nó trả về 0. Ví dụ, INSTR('Alice Tanaka', ' ') trả về 6 vì khoảng trắng ở vị trí thứ 6.

Kết hợp với SUBSTR và bạn có thể cắt chuỗi dựa trên dấu phân cách thay vì vị trí cố định. Đây là combo chủ lực để biến đổi chuỗi có độ dài thay đổi — «tách email quanh @», «trích xuất chỉ họ từ tên đầy đủ», v.v.

-- 1) INSTR đơn — kiểm tra vị trí khoảng trắng
SELECT name, INSTR(name, ' ') AS space_pos FROM staff;
-- 'Alice Tanaka' → 6, 'Bob Suzuki' → 4, ...

-- 2) Kết hợp với SUBSTR để trích xuất họ
SELECT name,
       SUBSTR(name, INSTR(name, ' ') + 1) AS last_name
FROM staff;

-- 3) Tách quanh '@' (ví dụ email)
SELECT INSTR('alice@example.com', '@'); -- 6
Cách INSTR + SUBSTR cắt họ
BướcBiểu thứcKết quả① Tìm vị tríkhoảng trắngINSTR('Alice Tanaka',' ')6② Tính vị tríbắt đầu của họ6 + 17③ Cắt từ đóđến cuốiSUBSTR('Alice Tanaka', 7)'Tanaka'
3 bước để trích xuất họ từ 'Alice Tanaka'. ① INSTR tìm vị trí khoảng trắng (ký tự thứ 6) → ② +1 tính bắt đầu của họ (ký tự thứ 7) → ③ SUBSTR cắt từ đó đến cuối, trả về 'Tanaka'.

Hãy tưởng tượng một yêu cầu: «trích xuất chỉ phần họ của mỗi tên đầy đủ và hiển thị top 5 theo thứ tự bảng chữ cái của họ». Trong staff, name có dạng «Alice Tanaka» — «tên khoảng trắng họ», phân tách bằng khoảng trắng nửa chiều rộng. Vì độ dài tên khác nhau, thay vì cắt tại vị trí cố định, dùng `INSTR` để tìm vị trí khoảng trắng rồi cắt sau đó.

① Từ bảng staff, lấy name`SUBSTR(name, INSTR(name, ' ') + 1)` với bí danh `last_name` — tổng 2 cột.

② Sắp xếp đa cấp: `last_name` tăng dần, với `name` tăng dần là tiêu chí phá vỡ khi bằng. Giới hạn ở 5 hàng đầu.

③ Kiểm tra kết quả là 5 hàng (David Sato / Emi Sato / Henry Sato / Bob Suzuki / Grace Suzuki).

SQL Editor

Chạy truy vấn để xem kết quả
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Trong console của khóa học này (SQLite), SELECT LENGTH('phở'); trả về gì?

Câu 2SELECT REPLACE('I LIKE APPLE', 'APPLE', 'BANANA'); trả về gì?

Câu 3SELECT SUBSTR('Alice Tanaka', 7, 6); trả về gì?