这篇更贴近"日常写业务"的 SQL,不讲理论,强调能直接拿去改。
一、按时间范围的常用查询
sql
-- 最近 7 天订单
SELECT *
FROM orders
WHERE create_time >= NOW() - INTERVAL 7 DAY;
-- 指定日期
SELECT *
FROM orders
WHERE create_time >= '2026-04-01 00:00:00'
AND create_time < '2026-04-02 00:00:00';
二、状态机更新(防止重复更新)
sql
-- 只允许从 UNPAID -> PAID
UPDATE orders
SET status = 'PAID', pay_time = NOW()
WHERE id = ? AND status = 'UNPAID';
三、库存扣减(防止超卖)
sql
UPDATE stock
SET quantity = quantity - 1
WHERE sku_id = ? AND quantity > 0;
配套判断:受影响行数为 0 就表示库存不足。
四、批量更新(避免一条条改)
sql
UPDATE user
SET status = 'DISABLED'
WHERE last_login < NOW() - INTERVAL 180 DAY;
五、存在即更新(UPSERT)
sql
INSERT INTO user_profile (user_id, nickname, avatar)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
nickname = VALUES(nickname),
avatar = VALUES(avatar);
六、批量插入(提高吞吐)
sql
INSERT INTO audit_log (user_id, action, create_time)
VALUES
(101, 'LOGIN', NOW()),
(102, 'LOGIN', NOW()),
(103, 'LOGIN', NOW());
七、分页查询(业务常规)
sql
-- 传统分页(页数不大可用)
SELECT id, user_id, status, create_time
FROM orders
ORDER BY create_time DESC
LIMIT 0, 20;
sql
-- 游标分页(更稳)
SELECT id, user_id, status, create_time
FROM orders
WHERE (create_time < ? OR (create_time = ? AND id < ?))
ORDER BY create_time DESC, id DESC
LIMIT 20;
八、模糊搜索(建议加前缀)
sql
-- 前缀匹配可用索引
SELECT * FROM user WHERE nickname LIKE '张%';
%张% 这种全模糊通常走不到索引。
九、查重(业务常用)
sql
SELECT email, COUNT(*) AS cnt
FROM user
GROUP BY email
HAVING cnt > 1;
十、取某用户最新一条记录
sql
SELECT *
FROM login_log
WHERE user_id = ?
ORDER BY create_time DESC
LIMIT 1;
十一、报表类统计(按天聚合)
sql
SELECT DATE(create_time) AS day, COUNT(*) AS cnt
FROM orders
WHERE create_time >= NOW() - INTERVAL 30 DAY
GROUP BY day
ORDER BY day;
十二、快速排除无效数据
sql
SELECT *
FROM orders
WHERE status IN ('PAID', 'SHIPPED')
AND deleted = 0;
最后总结
这类业务 SQL 的核心是三点:
- 写法清晰、能命中索引
- 更新条件有约束,避免重复或越界
- 批量操作优先,减少往返成本