SQL 提供了豐富的內建函式來處理字串、日期和時間資料,這些函式是資料處理工作的基礎。無論是格式化顯示、資料轉換還是日期計算,熟練掌握這些函式都能大幅提升開發效率。本文將深入探討 SQL 中常用的字串和日期時間函式,透過實際範例展示它們的應用場景和組合技巧。
分組查詢與聚合函式
在探討字串函式之前,先介紹分組查詢的基礎,因為它經常與字串處理結合使用。GROUP BY 子句讓我們能夠將資料依照特定欄位分組,並對每個分組進行聚合運算。
-- 建立測試資料表
-- 主題樂園資料表,包含位置資訊
CREATE TABLE theme_parks (
-- 樂園編號
park_id INT PRIMARY KEY AUTO_INCREMENT,
-- 樂園名稱
park_name VARCHAR(100),
-- 國家
country VARCHAR(50),
-- 州/省
state VARCHAR(50),
-- 城市
city VARCHAR(50),
-- 年度訪客數
annual_visitors INT
);
-- 插入測試資料
INSERT INTO theme_parks (park_name, country, state, city, annual_visitors) VALUES
('Magic Kingdom', 'USA', 'Florida', 'Orlando', 21000000),
('EPCOT', 'USA', 'Florida', 'Orlando', 12500000),
('Hollywood Studios', 'USA', 'Florida', 'Orlando', 11000000),
('Animal Kingdom', 'USA', 'Florida', 'Orlando', 13500000),
('Disneyland', 'USA', 'California', 'Anaheim', 18000000),
('Universal Studios', 'USA', 'California', 'Los Angeles', 9000000),
('Beto Carrero World', 'Brazil', 'Santa Catarina', 'Penha', 2000000),
('Beach Park', 'Brazil', 'Santa Catarina', 'Aquiraz', 800000);
-- 按國家和州統計樂園數量
-- GROUP BY 可以指定多個欄位進行多層分組
SELECT
country AS 國家,
state AS 州,
-- COUNT(*) 計算每個分組的資料筆數
COUNT(*) AS 樂園數量,
-- SUM() 計算訪客總數
SUM(annual_visitors) AS 年度總訪客數,
-- AVG() 計算平均訪客數
ROUND(AVG(annual_visitors), 0) AS 平均訪客數
FROM theme_parks
GROUP BY country, state
ORDER BY 年度總訪客數 DESC;
-- 結果:
-- 國家 | 州 | 樂園數量 | 年度總訪客數 | 平均訪客數
-- USA | Florida | 4 | 58000000 | 14500000
-- USA | California | 2 | 27000000 | 13500000
-- Brazil| Santa Catarina | 2 | 2800000 | 1400000
-- 只按國家統計
SELECT
country AS 國家,
COUNT(*) AS 樂園數量
FROM theme_parks
GROUP BY country;
-- 使用 HAVING 篩選分組結果
-- WHERE 是在分組前篩選,HAVING 是在分組後篩選
SELECT
country,
state,
COUNT(*) AS park_count,
SUM(annual_visitors) AS total_visitors
FROM theme_parks
GROUP BY country, state
-- HAVING 篩選訪客數超過 1000 萬的分組
HAVING SUM(annual_visitors) > 10000000;
字串連接函式
CONCAT 函式是最常用的字串處理函式之一,用於將多個字串值連接成一個字串。
-- 建立聯絡人資料表
CREATE TABLE contacts (
contact_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50),
last_name VARCHAR(50),
title VARCHAR(20),
phone VARCHAR(20),
email VARCHAR(100)
);
INSERT INTO contacts (first_name, last_name, title, phone, email) VALUES
('Alice', 'Chen', 'Ms.', '0912-345-678', 'alice.chen@email.com'),
('Bob', 'Wang', 'Mr.', '0923-456-789', 'bob.wang@email.com'),
('Charlie', 'Lin', 'Dr.', '0934-567-890', 'charlie.lin@email.com');
-- 基本字串連接
-- CONCAT() 將多個字串連接成一個
SELECT
-- 連接名字和姓氏,中間加空格
CONCAT(first_name, ' ', last_name) AS full_name
FROM contacts;
-- 結果:
-- full_name
-- Alice Chen
-- Bob Wang
-- Charlie Lin
-- 連接多個欄位建立完整資訊
SELECT
-- 連接稱謂、名字和姓氏
CONCAT(title, ' ', first_name, ' ', last_name) AS formal_name,
-- 連接姓名和電話
CONCAT(first_name, ' (', phone, ')') AS contact_info
FROM contacts;
-- CONCAT_WS:使用分隔符號連接
-- WS = With Separator
-- 第一個參數是分隔符號,後面是要連接的字串
SELECT
-- 使用逗號和空格作為分隔符號
CONCAT_WS(', ', last_name, first_name) AS name_formal,
-- 使用 | 作為分隔符號
CONCAT_WS(' | ', first_name, email, phone) AS contact_detail
FROM contacts;
-- 結果:
-- name_formal | contact_detail
-- Chen, Alice | Alice | alice.chen@email.com | 0912-345-678
-- 實用範例:建立郵寄地址
CREATE TABLE addresses (
address_id INT,
street VARCHAR(100),
city VARCHAR(50),
state VARCHAR(50),
zip_code VARCHAR(10),
country VARCHAR(50)
);
INSERT INTO addresses VALUES
(1, '123 Main Street', 'Taipei', 'Taiwan', '10001', 'Taiwan'),
(2, '456 Oak Avenue', 'Kaohsiung', 'Taiwan', '80001', 'Taiwan');
-- 建立完整地址
SELECT
CONCAT_WS(', ',
street,
city,
state,
zip_code,
country
) AS full_address
FROM addresses;
數值格式化函式
FORMAT 函式用於將數值格式化為更易讀的形式,特別適合處理大數字或需要特定小數位數的情況。
-- FORMAT 函式基本用法
-- FORMAT(數值, 小數位數)
-- 新增千位分隔符號
SELECT FORMAT(1234567, 0) AS formatted_number;
-- 結果:1,234,567
-- 指定小數位數
SELECT FORMAT(1234567.89123, 2) AS formatted_decimal;
-- 結果:1,234,567.89
-- 顯示更多小數位數
SELECT FORMAT(1234567.89, 5) AS extended_decimal;
-- 結果:1,234,567.89000
-- 實際應用:格式化人口資料
CREATE TABLE countries (
country_name VARCHAR(50),
population BIGINT,
gdp DECIMAL(15, 2)
);
INSERT INTO countries VALUES
('Taiwan', 23570000, 668500000000.00),
('Japan', 125800000, 4937400000000.00),
('South Korea', 51780000, 1810900000000.00);
-- 格式化顯示人口和 GDP
SELECT
country_name AS 國家,
-- 人口加上千位分隔符號
FORMAT(population, 0) AS 人口,
-- GDP 顯示兩位小數並加上貨幣符號
CONCAT('$', FORMAT(gdp, 2)) AS GDP
FROM countries;
-- 結果:
-- 國家 | 人口 | GDP
-- Taiwan | 23,570,000 | $668,500,000,000.00
-- Japan | 125,800,000 | $4,937,400,000,000.00
-- South Korea | 51,780,000 | $1,810,900,000,000.00
字串擷取函式
SQL 提供多種函式來擷取字串的特定部分,包括 LEFT、RIGHT 和 SUBSTRING。
-- LEFT 函式:從左側擷取指定數量的字元
-- LEFT(字串, 字元數)
SELECT LEFT('Hello World', 5) AS left_result;
-- 結果:Hello
-- RIGHT 函式:從右側擷取指定數量的字元
-- RIGHT(字串, 字元數)
SELECT RIGHT('Hello World', 5) AS right_result;
-- 結果:World
-- SUBSTRING 函式:從指定位置擷取指定長度的子字串
-- SUBSTRING(字串, 起始位置, 長度)
-- 注意:SQL 的位置從 1 開始計算
SELECT SUBSTRING('Hello World', 7, 5) AS substring_result;
-- 結果:World
-- 省略長度參數則擷取到字串結尾
SELECT SUBSTRING('Hello World', 7) AS to_end;
-- 結果:World
-- 實際應用:處理納稅人資料
CREATE TABLE taxpayers (
taxpayer_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50),
last_name VARCHAR(50),
-- 社會安全碼格式:XXX-XX-XXXX
social_security_no VARCHAR(11)
);
INSERT INTO taxpayers (first_name, last_name, social_security_no) VALUES
('Mick', 'Jagger', '123-45-7598'),
('Paul', 'McCartney', '234-56-1974'),
('Jimi', 'Hendrix', '345-67-3555');
-- 擷取姓氏前三個字元和 SSN 後四碼
SELECT
last_name AS 姓氏,
-- 姓氏前三個字元
LEFT(last_name, 3) AS 姓氏前三碼,
-- SSN 後四碼
RIGHT(social_security_no, 4) AS SSN後四碼
FROM taxpayers;
-- 結果:
-- 姓氏 | 姓氏前三碼 | SSN後四碼
-- Jagger | Jag | 7598
-- McCartney | McC | 1974
-- Hendrix | Hen | 3555
-- 使用 SUBSTRING 解析郵遞區號
-- 美國郵遞區號結構:
-- 第 1 碼:全國區域
-- 第 2-3 碼:地區中心
-- 第 4-5 碼:郵局
CREATE TABLE postal_addresses (
address_id INT,
zip_code VARCHAR(5)
);
INSERT INTO postal_addresses VALUES
(1, '94103'),
(2, '37188'),
(3, '96718');
SELECT
zip_code AS 郵遞區號,
-- 第一碼:全國區域
SUBSTRING(zip_code, 1, 1) AS 全國區域,
-- 第 2-3 碼:地區中心
SUBSTRING(zip_code, 2, 2) AS 地區中心,
-- 第 4-5 碼:郵局
SUBSTRING(zip_code, 4, 2) AS 郵局
FROM postal_addresses;
-- 結果:
-- 郵遞區號 | 全國區域 | 地區中心 | 郵局
-- 94103 | 9 | 41 | 03
-- 37188 | 3 | 71 | 88
-- 96718 | 9 | 67 | 18
大小寫轉換函式
UPPER 和 LOWER 函式用於轉換字串的大小寫。
-- UPPER:轉換為大寫
SELECT UPPER('hello world') AS upper_result;
-- 結果:HELLO WORLD
-- LOWER:轉換為小寫
SELECT LOWER('HELLO WORLD') AS lower_result;
-- 結果:hello world
-- 實際應用:標準化資料
SELECT
last_name AS 原始姓氏,
UPPER(last_name) AS 大寫姓氏,
LOWER(last_name) AS 小寫姓氏
FROM taxpayers;
-- 組合應用:建立標準化的識別碼
-- 需求:姓氏前三碼大寫 + SSN 後四碼
SELECT
last_name,
social_security_no,
-- 使用 CONCAT 組合 UPPER、LEFT 和 RIGHT
CONCAT(
UPPER(LEFT(last_name, 3)),
RIGHT(social_security_no, 4)
) AS taxpayer_code
FROM taxpayers;
-- 結果:
-- last_name | social_security_no | taxpayer_code
-- Jagger | 123-45-7598 | JAG7598
-- McCartney | 234-56-1974 | MCC1974
-- Hendrix | 345-67-3555 | HEN3555
字串修剪函式
TRIM 系列函式用於移除字串中不需要的字元,通常是空白字元。
-- TRIM:移除字串兩端的空白
SELECT TRIM(' hello world ') AS trimmed;
-- 結果:'hello world'
-- LTRIM:只移除左側空白
SELECT LTRIM(' hello world ') AS left_trimmed;
-- 結果:'hello world '
-- RTRIM:只移除右側空白
SELECT RTRIM(' hello world ') AS right_trimmed;
-- 結果:' hello world'
-- TRIM 進階用法:移除指定字元
-- 語法:TRIM([LEADING|TRAILING|BOTH] 字元 FROM 字串)
-- 移除前導星號
SELECT TRIM(LEADING '*' FROM '**instructions**') AS result;
-- 結果:'instructions**'
-- 移除尾隨星號
SELECT TRIM(TRAILING '*' FROM '**instructions**') AS result;
-- 結果:'**instructions'
-- 移除兩端星號
SELECT TRIM(BOTH '*' FROM '**instructions**') AS result;
-- 結果:'instructions'
-- 省略 LEADING/TRAILING/BOTH 時預設為 BOTH
SELECT TRIM('*' FROM '**instructions**') AS result;
-- 結果:'instructions'
-- 實際應用:清理資料
CREATE TABLE raw_data (
id INT,
messy_name VARCHAR(100),
messy_code VARCHAR(50)
);
INSERT INTO raw_data VALUES
(1, ' Alice Chen ', '###ABC123###'),
(2, ' Bob Wang ', '***XYZ789***');
-- 清理資料
SELECT
id,
-- 移除姓名的前後空白
TRIM(messy_name) AS clean_name,
-- 移除代碼的前後 # 和 *
TRIM(BOTH '#' FROM TRIM(BOTH '*' FROM messy_code)) AS clean_code
FROM raw_data;
字串函式的組合應用
將多個字串函式組合使用,可以完成複雜的資料處理任務。
-- 綜合範例:建立專業的識別碼系統
-- 需求:
-- 1. 姓氏前 3 碼大寫
-- 2. 名字首字母大寫
-- 3. SSN 後 4 碼
-- 格式:JAG-M-7598
SELECT
first_name,
last_name,
social_security_no,
CONCAT(
-- 姓氏前三碼大寫
UPPER(LEFT(last_name, 3)),
'-',
-- 名字首字母大寫
UPPER(LEFT(first_name, 1)),
'-',
-- SSN 後四碼
RIGHT(social_security_no, 4)
) AS professional_id
FROM taxpayers;
-- 結果:
-- first_name | last_name | social_security_no | professional_id
-- Mick | Jagger | 123-45-7598 | JAG-M-7598
-- Paul | McCartney | 234-56-1974 | MCC-P-1974
-- Jimi | Hendrix | 345-67-3555 | HEN-J-3555
-- 資料標準化範例
CREATE TABLE customer_data (
customer_id INT,
raw_name VARCHAR(100),
raw_email VARCHAR(100)
);
INSERT INTO customer_data VALUES
(1, ' ALICE CHEN ', ' Alice.Chen@EMAIL.COM '),
(2, ' bob wang ', ' BOB.WANG@email.com ');
-- 清理並標準化資料
SELECT
customer_id,
-- 姓名:去除空白後首字大寫
CONCAT(
UPPER(LEFT(TRIM(raw_name), 1)),
LOWER(SUBSTRING(TRIM(raw_name), 2))
) AS formatted_name,
-- Email:全部轉小寫並去除空白
LOWER(TRIM(raw_email)) AS formatted_email
FROM customer_data;
日期和時間函式
SQL 提供完整的日期時間函式,用於取得當前時間、擷取日期部分以及進行日期運算。
取得當前日期時間
-- CURDATE():傳回當前日期(YYYY-MM-DD)
SELECT CURDATE() AS current_date_value;
-- 結果:2025-11-27
-- CURTIME():傳回當前時間(HH:MM:SS)
SELECT CURTIME() AS current_time_value;
-- 結果:14:30:45
-- NOW():傳回當前日期和時間(YYYY-MM-DD HH:MM:SS)
SELECT NOW() AS current_datetime;
-- 結果:2025-11-27 14:30:45
-- 同義函式
-- CURRENT_DATE、CURRENT_DATE() = CURDATE()
-- CURRENT_TIME、CURRENT_TIME() = CURTIME()
-- CURRENT_TIMESTAMP、CURRENT_TIMESTAMP() = NOW()
SELECT
CURDATE() AS date1,
CURRENT_DATE AS date2,
CURRENT_DATE() AS date3;
-- 三個結果相同
日期時間擷取函式
-- YEAR():擷取年份
SELECT YEAR('2025-11-27') AS year_value;
-- 結果:2025
-- MONTH():擷取月份
SELECT MONTH('2025-11-27') AS month_value;
-- 結果:11
-- DAY():擷取日期
SELECT DAY('2025-11-27') AS day_value;
-- 結果:27
-- HOUR()、MINUTE()、SECOND():擷取時間部分
SELECT
HOUR('14:30:45') AS hour_value,
MINUTE('14:30:45') AS minute_value,
SECOND('14:30:45') AS second_value;
-- 結果:14, 30, 45
-- EXTRACT():通用的日期部分擷取函式
-- 語法:EXTRACT(單位 FROM 日期時間)
SELECT
EXTRACT(YEAR FROM '2025-11-27 14:30:45') AS year_val,
EXTRACT(MONTH FROM '2025-11-27 14:30:45') AS month_val,
EXTRACT(DAY FROM '2025-11-27 14:30:45') AS day_val,
EXTRACT(HOUR FROM '2025-11-27 14:30:45') AS hour_val,
EXTRACT(MINUTE FROM '2025-11-27 14:30:45') AS minute_val;
-- DAYNAME():傳回星期幾
SELECT DAYNAME('2025-11-27') AS day_name;
-- 結果:Thursday
-- MONTHNAME():傳回月份名稱
SELECT MONTHNAME('2025-11-27') AS month_name;
-- 結果:November
-- DAYOFWEEK():傳回星期幾(1=Sunday, 7=Saturday)
SELECT DAYOFWEEK('2025-11-27') AS dow;
-- 結果:5(星期四)
-- DAYOFYEAR():傳回一年中的第幾天
SELECT DAYOFYEAR('2025-11-27') AS doy;
-- 結果:331
日期加減運算
DATE_ADD 和 DATE_SUB 函式用於對日期進行加減運算。
-- DATE_ADD():在日期上加上時間間隔
-- 語法:DATE_ADD(日期, INTERVAL 數量 單位)
-- 加 7 天
SELECT DATE_ADD('2025-11-27', INTERVAL 7 DAY) AS plus_7_days;
-- 結果:2025-12-04
-- 加 2 個月
SELECT DATE_ADD('2025-11-27', INTERVAL 2 MONTH) AS plus_2_months;
-- 結果:2026-01-27
-- 加 1 年
SELECT DATE_ADD('2025-11-27', INTERVAL 1 YEAR) AS plus_1_year;
-- 結果:2026-11-27
-- 加 3 小時
SELECT DATE_ADD('2025-11-27 14:30:00', INTERVAL 3 HOUR) AS plus_3_hours;
-- 結果:2025-11-27 17:30:00
-- DATE_SUB():從日期減去時間間隔
-- 語法:DATE_SUB(日期, INTERVAL 數量 單位)
-- 減 30 天
SELECT DATE_SUB('2025-11-27', INTERVAL 30 DAY) AS minus_30_days;
-- 結果:2025-10-28
-- 減 6 個月
SELECT DATE_SUB('2025-11-27', INTERVAL 6 MONTH) AS minus_6_months;
-- 結果:2025-05-27
-- 也可以使用負數的 INTERVAL 來達到相同效果
SELECT DATE_ADD('2025-11-27', INTERVAL -7 DAY) AS also_minus_7_days;
-- 結果:2025-11-20
-- 常用的 INTERVAL 單位
-- SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR
-- DAY_HOUR, DAY_MINUTE, DAY_SECOND
-- HOUR_MINUTE, HOUR_SECOND
-- MINUTE_SECOND
-- 複合間隔
SELECT DATE_ADD('2025-11-27 14:30:00', INTERVAL '1:30' HOUR_MINUTE) AS plus_1h30m;
-- 結果:2025-11-27 16:00:00
日期差異計算
-- DATEDIFF():計算兩個日期之間的天數差異
-- 語法:DATEDIFF(日期1, 日期2)
-- 傳回 日期1 - 日期2 的天數
SELECT DATEDIFF('2025-12-31', '2025-11-27') AS days_until_year_end;
-- 結果:34
SELECT DATEDIFF('2025-11-27', '2025-01-01') AS days_since_year_start;
-- 結果:330
-- TIMESTAMPDIFF():計算兩個時間戳之間的差異
-- 語法:TIMESTAMPDIFF(單位, 時間1, 時間2)
-- 傳回 時間2 - 時間1 的差異
-- 計算年份差異
SELECT TIMESTAMPDIFF(YEAR, '2020-05-15', '2025-11-27') AS years_diff;
-- 結果:5
-- 計算月份差異
SELECT TIMESTAMPDIFF(MONTH, '2025-01-01', '2025-11-27') AS months_diff;
-- 結果:10
-- 計算小時差異
SELECT TIMESTAMPDIFF(HOUR, '2025-11-27 08:00:00', '2025-11-27 17:30:00') AS hours_diff;
-- 結果:9
日期格式化
-- DATE_FORMAT():將日期格式化為指定格式
-- 語法:DATE_FORMAT(日期, 格式字串)
-- 常用格式符號:
-- %Y:四位數年份(2025)
-- %y:兩位數年份(25)
-- %m:兩位數月份(01-12)
-- %c:月份(1-12)
-- %d:兩位數日期(01-31)
-- %e:日期(1-31)
-- %H:24 小時制小時(00-23)
-- %h:12 小時制小時(01-12)
-- %i:分鐘(00-59)
-- %s:秒(00-59)
-- %p:AM 或 PM
-- %W:星期全名
-- %a:星期縮寫
-- %M:月份全名
-- %b:月份縮寫
-- 格式化範例
SELECT
DATE_FORMAT('2025-11-27 14:30:45', '%Y-%m-%d') AS date_only,
DATE_FORMAT('2025-11-27 14:30:45', '%Y年%m月%d日') AS chinese_date,
DATE_FORMAT('2025-11-27 14:30:45', '%W, %M %e, %Y') AS formal_date,
DATE_FORMAT('2025-11-27 14:30:45', '%h:%i %p') AS time_12h;
-- 結果:
-- date_only | chinese_date | formal_date | time_12h
-- 2025-11-27 | 2025年11月27日 | Thursday, November 27, 2025 | 02:30 PM
綜合應用範例
以下範例展示如何結合字串和日期時間函式進行實際的資料處理。
-- 建立事件資料表
CREATE TABLE events (
event_id INT PRIMARY KEY AUTO_INCREMENT,
event_name VARCHAR(100),
event_datetime DATETIME,
location VARCHAR(100),
organizer_first VARCHAR(50),
organizer_last VARCHAR(50)
);
INSERT INTO events (event_name, event_datetime, location, organizer_first, organizer_last) VALUES
('技術研討會', '2025-12-15 09:00:00', ' 台北國際會議中心 ', 'Alice', 'Chen'),
('產品發表會', '2025-12-20 14:00:00', ' 高雄展覽館 ', 'Bob', 'Wang'),
('年度聚會', '2025-12-31 18:00:00', ' 台中酒店 ', 'Charlie', 'Lin');
-- 建立完整的活動報表
SELECT
event_id AS 編號,
event_name AS 活動名稱,
-- 格式化日期時間
DATE_FORMAT(event_datetime, '%Y年%m月%d日 %H:%i') AS 活動時間,
-- 計算距今天數
DATEDIFF(event_datetime, CURDATE()) AS 倒數天數,
-- 清理地點資料
TRIM(location) AS 地點,
-- 組合主辦人姓名
CONCAT(organizer_last, organizer_first) AS 主辦人,
-- 建立活動代碼
CONCAT(
UPPER(LEFT(event_name, 2)),
'-',
DATE_FORMAT(event_datetime, '%m%d')
) AS 活動代碼
FROM events
ORDER BY event_datetime;
-- 建立會員資料表
CREATE TABLE members (
member_id INT PRIMARY KEY AUTO_INCREMENT,
full_name VARCHAR(100),
email VARCHAR(100),
join_date DATE,
membership_type VARCHAR(20)
);
INSERT INTO members VALUES
(1, ' chen alice ', 'ALICE@EMAIL.COM', '2020-03-15', 'Premium'),
(2, ' wang bob ', 'BOB@email.COM', '2021-07-22', 'Standard'),
(3, ' lin charlie ', 'charlie@EMAIL.com', '2023-01-10', 'Premium');
-- 會員資料清理與分析報表
SELECT
member_id,
-- 清理並格式化姓名(首字大寫)
CONCAT(
UPPER(LEFT(TRIM(full_name), 1)),
LOWER(SUBSTRING(TRIM(full_name), 2))
) AS formatted_name,
-- Email 轉小寫
LOWER(TRIM(email)) AS formatted_email,
-- 格式化加入日期
DATE_FORMAT(join_date, '%Y年%m月%d日') AS join_date_formatted,
-- 計算會員年資
TIMESTAMPDIFF(YEAR, join_date, CURDATE()) AS years_membership,
-- 計算會員天數
DATEDIFF(CURDATE(), join_date) AS days_membership,
-- 會員狀態
CASE
WHEN TIMESTAMPDIFF(YEAR, join_date, CURDATE()) >= 3 THEN '資深會員'
WHEN TIMESTAMPDIFF(YEAR, join_date, CURDATE()) >= 1 THEN '一般會員'
ELSE '新會員'
END AS member_status,
membership_type
FROM members
ORDER BY join_date;
效能最佳化建議
在使用字串和日期時間函式時,需要注意效能影響:
-- 效能考量
-- 不佳的做法:在 WHERE 子句中對欄位使用函式
-- 這會導致無法使用索引
SELECT * FROM events
WHERE YEAR(event_datetime) = 2025;
-- 較佳的做法:使用範圍條件
SELECT * FROM events
WHERE event_datetime >= '2025-01-01'
AND event_datetime < '2026-01-01';
-- 不佳的做法:對大量資料使用字串函式
SELECT * FROM members
WHERE LOWER(email) = 'alice@email.com';
-- 較佳的做法:在應用程式層處理,或使用生成的欄位
-- 或在插入時就標準化資料
-- 使用生成的欄位提升效能(MySQL 5.7+)
ALTER TABLE members
ADD COLUMN email_lower VARCHAR(100)
GENERATED ALWAYS AS (LOWER(email)) STORED;
-- 然後可以在生成的欄位上建立索引
CREATE INDEX idx_email_lower ON members(email_lower);
SQL 的字串和日期時間函式是資料處理的基礎工具。透過本文的介紹,讀者應該能夠掌握這些函式的基本用法和組合技巧。在實際應用中,建議根據具體需求選擇適當的函式,並注意效能影響。熟練運用這些函式,能夠大幅提升資料處理的效率和品質。