SUBSTRING() / SUBSTR() 函數 (SQL Substring Function)
SUBSTRING() (或 SUBSTR()) 函數用於從字串中擷取指定位置、指定長度的子字串。這是 SQL 中最常用的字串處理函數之一。
各資料庫的函數名稱
| 資料庫 | 函數名稱 | 負數起始位置 |
|---|---|---|
| MySQL | SUBSTRING(), SUBSTR(), MID() | ✅ 支援 |
| SQL Server | SUBSTRING() | ❌ 不支援 |
| PostgreSQL | SUBSTRING(), SUBSTR() | ❌ 不支援 |
| Oracle | SUBSTR() | ✅ 支援 |
| SQLite | SUBSTR() | ✅ 支援 |
語法 (Syntax)
-- 標準語法
SUBSTRING(string, start, length)
SUBSTRING(string FROM start FOR length)
-- MySQL / Oracle / SQLite
SUBSTR(string, start, length)
string:原始字串或欄位名稱start:起始位置 (從 1 開始計算)length:要擷取的字元數 (可選,省略則擷取到結尾)
基本範例
SELECT SUBSTRING('Hello World', 1, 5) AS Result;
-- 結果:'Hello'
SELECT SUBSTRING('Hello World', 7, 5) AS Result;
-- 結果:'World'
SELECT SUBSTRING('Hello World', 7) AS Result;
-- 結果:'World' (擷取到結尾)
從資料表欄位擷取
products 資料表:
| product_code | name |
|---|---|
| PRD-001-TW | 筆記型電腦 |
| PRD-002-US | 智慧手機 |
擷取產品代碼前綴
SELECT SUBSTRING(product_code, 1, 3) AS prefix, name
FROM products;
結果:
| prefix | name |
|---|---|
| PRD | 筆記型電腦 |
| PRD | 智慧手機 |
擷取流水號
SELECT SUBSTRING(product_code, 5, 3) AS serial_number
FROM products;
結果:
| serial_number |
|---|
| 001 |
| 002 |
負數起始位置 (MySQL / Oracle / SQLite)
負數表示從字串結尾開始計算位置:
-- MySQL / Oracle
SELECT SUBSTR(product_code, -2) AS country_code
FROM products;
結果:
| country_code |
|---|
| TW |
| US |
SQL Server 替代方案
SQL Server 不支援負數,需搭配 LEN() 函數:
-- SQL Server:取得最後 2 個字元
SELECT SUBSTRING(product_code, LEN(product_code) - 1, 2) AS country_code
FROM products;
搭配其他函數使用
1. 搭配 CHARINDEX / LOCATE / INSTR
擷取特定字元之後的內容:
-- SQL Server:取得 email 的網域
SELECT SUBSTRING(email, CHARINDEX('@', email) + 1, 100) AS domain
FROM users;
-- MySQL
SELECT SUBSTRING(email, LOCATE('@', email) + 1) AS domain
FROM users;
-- Oracle
SELECT SUBSTR(email, INSTR(email, '@') + 1) AS domain
FROM users;
2. 搭配 LENGTH / LEN
-- 取得除了最後 3 個字元以外的內容
-- MySQL
SELECT SUBSTRING(name, 1, LENGTH(name) - 3) AS trimmed
FROM products;
-- SQL Server
SELECT SUBSTRING(name, 1, LEN(name) - 3) AS trimmed
FROM products;
3. 搭配 CONCAT
-- 隱藏部分電話號碼
SELECT CONCAT(
SUBSTRING(phone, 1, 4),
'****',
SUBSTRING(phone, 9)
) AS masked_phone
FROM customers;
-- 結果:0912****890
實際應用範例
1. 擷取日期部分
-- 從 'YYYY-MM-DD' 格式擷取年月日
SELECT
SUBSTRING(date_string, 1, 4) AS Year,
SUBSTRING(date_string, 6, 2) AS Month,
SUBSTRING(date_string, 9, 2) AS Day
FROM orders;
2. 解析固定格式資料
-- 身分證字號解析 (台灣格式)
SELECT
SUBSTRING(id_number, 1, 1) AS area_code,
SUBSTRING(id_number, 2, 1) AS gender
FROM citizens;
3. 資料脫敏
-- 隱藏 email 中間部分
SELECT
CONCAT(
LEFT(email, 2),
'***',
SUBSTRING(email, LOCATE('@', email))
) AS masked_email
FROM users;
-- 結果:jo***@example.com
4. 產生縮寫
-- 取得名字的首字母
SELECT
CONCAT(
SUBSTRING(first_name, 1, 1), '.',
SUBSTRING(last_name, 1, 1), '.'
) AS initials
FROM employees;
-- 結果:J.D.
注意事項
索引從 1 開始:SQL 的字串索引從 1 開始,不是 0。
超出範圍:如果
start + length超出字串長度,只會返回實際存在的字元。NULL 處理:如果輸入字串為 NULL,結果也是 NULL。
相關主題
- LEFT() / RIGHT() - 取得左/右側字元
- MID() - MySQL 的另一個子字串函數
- CHARINDEX() / INSTR() - 搜尋字元位置
- LENGTH() - 取得字串長度