引言

MySQL提供了丰富的内置函数来处理字符串和日期。掌握这些函数能大幅提升开发效率。


一、字符串函数

1.1 CONCAT() / CONCAT_WS() - 拼接

-- CONCAT:拼接字符串
SELECT CONCAT('Hello', ' ', 'World');  -- Hello World

-- CONCAT_WS:指定分隔符拼接
SELECT CONCAT_WS('-', '2024', '11', '21');  -- 2024-11-21

-- 实战:拼接姓名
SELECT CONCAT(last_name, first_name) AS full_name FROM users;

-- 处理NULL
SELECT CONCAT('Hello', NULL);  -- NULL
SELECT CONCAT_WS(',', 'A', NULL, 'C');  -- A,C(忽略NULL)

1.2 SUBSTRING() / SUBSTR() - 截取

-- SUBSTRING(str, pos, len)
SELECT SUBSTRING('Hello World', 1, 5);  -- Hello(从位置1开始,长度5)
SELECT SUBSTRING('Hello World', 7);     -- World(从位置7到结尾)
SELECT SUBSTRING('Hello World', -5);    -- World(从右边第5个)

-- 实战:提取手机号后4位
SELECT SUBSTRING(phone, -4) FROM users;

1.3 LENGTH() / CHAR_LENGTH() - 长度

-- LENGTH:字节长度
SELECT LENGTH('Hello');      -- 5
SELECT LENGTH('你好');       -- 6(UTF-8,每个汉字3字节)

-- CHAR_LENGTH:字符长度
SELECT CHAR_LENGTH('Hello'); -- 5
SELECT CHAR_LENGTH('你好');  -- 2

-- 实战:过滤长度
SELECT * FROM products WHERE CHAR_LENGTH(name) > 10;

1.4 UPPER() / LOWER() - 大小写

SELECT UPPER('hello');  -- HELLO
SELECT LOWER('WORLD');  -- world

-- 实战:不区分大小写查询
SELECT * FROM users WHERE LOWER(email) = 'user@example.com';

1.5 TRIM() / LTRIM() / RTRIM() - 去空格

SELECT TRIM('  Hello  ');          -- 'Hello'
SELECT LTRIM('  Hello  ');         -- 'Hello  '
SELECT RTRIM('  Hello  ');         -- '  Hello'
SELECT TRIM('x' FROM 'xxxHelloxxx');  -- 'Hello'

1.6 REPLACE() - 替换

SELECT REPLACE('Hello World', 'World', 'MySQL');  -- Hello MySQL

-- 实战:隐藏手机号中间4位
SELECT CONCAT(
    SUBSTRING(phone, 1, 3),
    '****',
    SUBSTRING(phone, -4)
) AS masked_phone
FROM users;

1.7 INSTR() / LOCATE() - 查找位置

SELECT INSTR('Hello World', 'World');  -- 7
SELECT LOCATE('o', 'Hello World');     -- 5
SELECT LOCATE('o', 'Hello World', 6);  -- 8(从第6个位置开始找)

1.8 LEFT() / RIGHT() - 左右截取

SELECT LEFT('Hello World', 5);   -- Hello
SELECT RIGHT('Hello World', 5);  -- World

二、日期时间函数

2.1 NOW() / CURDATE() / CURTIME()

SELECT NOW();       -- 2024-11-21 19:00:00(当前日期时间)
SELECT CURDATE();   -- 2024-11-21(当前日期)
SELECT CURTIME();   -- 19:00:00(当前时间)
SELECT SYSDATE();   -- 2024-11-21 19:00:00(系统时间)

2.2 DATE_FORMAT() - 格式化

-- DATE_FORMAT(date, format)
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');              -- 2024-11-21
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日');           -- 2024年11月21日
SELECT DATE_FORMAT(NOW(), '%H:%i:%s');              -- 19:00:00
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');     -- 2024-11-21 19:00:00
SELECT DATE_FORMAT(NOW(), '%W, %M %d, %Y');         -- Thursday, November 21, 2024

常用格式符

  • %Y:4位年份
  • %m:2位月份
  • %d:2位日期
  • %H:24小时制
  • %i:分钟
  • %s:秒
  • %W:星期名
  • %M:月份名

2.3 STR_TO_DATE() - 字符串转日期

SELECT STR_TO_DATE('2024-11-21', '%Y-%m-%d');                -- 2024-11-21
SELECT STR_TO_DATE('21/11/2024', '%d/%m/%Y');                -- 2024-11-21
SELECT STR_TO_DATE('2024年11月21日', '%Y年%m月%d日');        -- 2024-11-21

2.4 DATE_ADD() / DATE_SUB() - 日期加减

-- DATE_ADD(date, INTERVAL expr unit)
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);      -- 明天
SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH);    -- 下个月
SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR);     -- 明年
SELECT DATE_ADD(NOW(), INTERVAL -7 DAY);     -- 7天前

-- DATE_SUB
SELECT DATE_SUB(NOW(), INTERVAL 1 WEEK);     -- 1周前
SELECT DATE_SUB(NOW(), INTERVAL 30 DAY);     -- 30天前

-- 实战:查询最近7天的订单
SELECT * FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);

2.5 DATEDIFF() - 日期差

-- DATEDIFF(date1, date2):返回天数差
SELECT DATEDIFF('2024-11-21', '2024-11-01');   -- 20
SELECT DATEDIFF(NOW(), '2024-01-01');          -- 距离今年1月1日的天数

-- 实战:计算会员天数
SELECT name,
       DATEDIFF(NOW(), register_date) AS member_days
FROM users;

2.6 TIMESTAMPDIFF() - 更精确的时间差

-- TIMESTAMPDIFF(unit, datetime1, datetime2)
SELECT TIMESTAMPDIFF(SECOND, '2024-11-21 10:00:00', '2024-11-21 11:00:00');  -- 3600
SELECT TIMESTAMPDIFF(MINUTE, '2024-11-21 10:00:00', '2024-11-21 11:00:00');  -- 60
SELECT TIMESTAMPDIFF(HOUR, '2024-11-21 10:00:00', '2024-11-21 11:00:00');    -- 1
SELECT TIMESTAMPDIFF(DAY, '2024-11-01', '2024-11-21');                       -- 20
SELECT TIMESTAMPDIFF(MONTH, '2024-01-01', '2024-11-21');                     -- 10
SELECT TIMESTAMPDIFF(YEAR, '2020-01-01', '2024-11-21');                      -- 4

2.7 EXTRACT() - 提取日期部分

SELECT EXTRACT(YEAR FROM NOW());    -- 2024
SELECT EXTRACT(MONTH FROM NOW());   -- 11
SELECT EXTRACT(DAY FROM NOW());     -- 21
SELECT EXTRACT(HOUR FROM NOW());    -- 19

-- 或使用专用函数
SELECT YEAR(NOW()), MONTH(NOW()), DAY(NOW());

2.8 DAYOFWEEK() / WEEKDAY() - 星期

SELECT DAYOFWEEK(NOW());   -- 1-7(周日=1)
SELECT WEEKDAY(NOW());     -- 0-6(周一=0)
SELECT DAYNAME(NOW());     -- Thursday

2.9 LAST_DAY() - 月末

SELECT LAST_DAY('2024-11-21');  -- 2024-11-30
SELECT LAST_DAY(NOW());          -- 本月最后一天

三、实战案例

案例1:生成订单编号

SELECT CONCAT(
    'ORD',
    DATE_FORMAT(NOW(), '%Y%m%d'),
    LPAD(id, 6, '0')
) AS order_no
FROM orders;
-- 结果:ORD20241121000001

案例2:按月统计

SELECT DATE_FORMAT(created_at, '%Y-%m') AS month,
       COUNT(*) AS order_count,
       SUM(amount) AS total_amount
FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY month;

案例3:计算年龄

SELECT name,
       birthday,
       TIMESTAMPDIFF(YEAR, birthday, NOW()) AS age
FROM users;

案例4:格式化显示

-- 显示"3天前"、"1小时前"
SELECT
    CASE
        WHEN TIMESTAMPDIFF(MINUTE, created_at, NOW()) < 60
            THEN CONCAT(TIMESTAMPDIFF(MINUTE, created_at, NOW()), '分钟前')
        WHEN TIMESTAMPDIFF(HOUR, created_at, NOW()) < 24
            THEN CONCAT(TIMESTAMPDIFF(HOUR, created_at, NOW()), '小时前')
        WHEN TIMESTAMPDIFF(DAY, created_at, NOW()) < 30
            THEN CONCAT(TIMESTAMPDIFF(DAY, created_at, NOW()), '天前')
        ELSE DATE_FORMAT(created_at, '%Y-%m-%d')
    END AS time_display
FROM articles;

四、总结

常用函数速查

字符串

  • 拼接:CONCAT、CONCAT_WS
  • 截取:SUBSTRING、LEFT、RIGHT
  • 长度:LENGTH、CHAR_LENGTH
  • 大小写:UPPER、LOWER
  • 处理:TRIM、REPLACE

日期时间

  • 获取:NOW、CURDATE、CURTIME
  • 格式化:DATE_FORMAT、STR_TO_DATE
  • 计算:DATE_ADD、DATE_SUB、DATEDIFF
  • 提取:YEAR、MONTH、DAY、EXTRACT

记忆口诀

字符串函数多又全,CONCAT拼接SUBSTRING截,
UPPER大写LOWER小,TRIM去空REPLACE换。
日期函数也常用,NOW当前FORMAT格式,
ADD增加SUB减少,DATEDIFF计算天数差。

本文字数:约3,200字 难度等级:⭐⭐(SQL进阶)