欢迎来到「SQL代码整形医院」!今天我们将化身"代码园丁",用一家因SQL代码混乱导致全员加班的虚拟电商公司案例,教你如何把"祖传屎山代码"修剪成"清爽可维护的艺术品"。
SELECT a.id,b.total,c.name FROM tbl_user a JOIN order_tbl b ON a.id=b.uid JOIN item c ON b.iid=c.id WHERE a.flag=1 AND b.ctime>'2023-01-01' ORDER BY 2 DESC LIMIT 100;
问题诊断报告:
a/b/c
像摩斯密码tbl_user
和order_tbl
命名风格精分ORDER BY 2
是隐藏的定时炸弹整形手术方案:
-- 目标:查询活跃用户的订单排行榜
SELECT
users.user_id AS user_id, -- 用户ID
orders.total_amount AS pay_total,
items.item_name AS product_name
FROM
users
INNER JOIN orders
ON users.user_id = orders.user_id
INNER JOIN items
ON orders.item_id = items.item_id
WHERE
users.status = 'active'
AND orders.created_time > '2023-01-01'
ORDER BY
orders.total_amount DESC -- 按支付金额降序
LIMIT 100;
整洁代码七大法则:
total_amount
而非total
JOIN
像高速公路指示牌一样清晰user_id
vs uid
只能选一个!status = 'active'
比flag = 1
更友好ORDER BY 2
是同事友谊的粉碎机-- 罪状1:废话文学奖
SELECT user_id FROM users; -- 这里查询用户ID
-- 罪状2:考古注释
/* 2015年王工写的 千万别改! */
-- (实际代码已被改过20次)
-- 罪状3:发泄式TODO
# TODO:这坨代码需要重构(然后三年没动)
/*
[LTV计算逻辑]
目标:计算用户生命周期价值
业务规则:
- 仅统计近3年有消费用户
- 退款订单需扣除金额
版本记录:
- 2023-05 初版(张小明)
- 2024-02 增加汇率转换逻辑
*/
WITH user_orders AS (
-- 步骤1:清洗有效订单数据
SELECT
user_id,
SUM(
CASE
WHEN currency = 'USD' THEN amount * 7.2
ELSE amount
END
) AS total_cny
FROM
orders
WHERE
order_status NOT IN ('cancelled', 'refunded')
AND created_time > CURRENT_DATE - INTERVAL 3 YEAR
GROUP BY
user_id
)
...
-- 文件:promotion_analysis.sql
SELECT AVG(amount) FROM orders
WHERE created_time BETWEEN '2024-06-01' AND '2024-06-18'
AND amount > 100;
-- 文件:quarter_report.sql
SELECT AVG(amount) FROM orders
WHERE created_time BETWEEN '2024-04-01' AND '2024-06-30'
AND amount > 100;
重构手术方案:
-- 创建可配置视图
CREATE VIEW high_value_orders AS
SELECT *
FROM orders
WHERE amount > 100; -- 高价值订单定义
-- 复用案例
SELECT
AVG(amount) AS avg_amount,
COUNT(*) AS order_count
FROM
high_value_orders
WHERE
created_time BETWEEN @start_date AND @end_date;
-- 进阶版:参数化存储过程
DELIMITER $$
CREATE PROCEDURE GetOrderStats(
IN start_date DATE,
IN end_date DATE
)
BEGIN
SELECT
AVG(amount) AS avg_amount,
COUNT(*) AS order_count
FROM
high_value_orders
WHERE
created_time BETWEEN start_date AND end_date;
END$$
DELIMITER ;
1. [ ] 有没有人偷偷用了SELECT *?(抓住罚款50)
2. [ ] WHERE条件字段穿"索引外套"了吗?
3. [ ] 事务范围是不是比老板的胃还大?
4. [ ] 有没有在SQL里写业务逻辑(判死刑!)
5. [ ] 分页查询是不是用的自杀式LIMIT?
6. [ ] 字段别名有没有用`a1/a2`这类密码?
7. [ ] 有没有处理NULL值这个"隐形杀手"?
-- 提交的代码:
SELECT
u.id,
o.total
FROM
user u
JOIN order o ON u.id = o.uid
WHERE
o.time > '2024-01-01';
-- 审查员毒舌点评:
1. 表别名`u/o`是要参加极简主义大赛吗?
2. `user`表字段`id`和`order`表`uid`命名精分
3. 没有指定排序规则,结果随机跳舞吗?
4. 时间字段没有索引,查询准备跑一年?
# 生产环境直接操作
mysql> ALTER TABLE users ADD COLUMN phone VARCHAR(20);
Query OK, 0 rows affected (30 min 22.34 sec)
-- 然后忘记在其他环境执行,导致测试环境爆炸
sql_scripts
├── ddl
│ └── 20240301_alter_users_add_phone.sql
├── dml
│ └── 20240302_backfill_user_phones.sql
└── procedures
└── sp_get_order_stats.sql
提交示例:
git commit -m "feat: 新增用户手机号字段
- 新增phone字段存储加密手机号
- 添加唯一索引防止重复
- 相关文档见Wiki #123"
三大纪律:
CREATE TABLE IF NOT EXISTS users (...);
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone...
自动化工具套餐:
# SQL格式化神器
sqlformat --keywords upper -r ugly.sql > beautiful.sql
# 版本差异对比
git diff --word-diff HEAD~1:ugly.sql ugly.sql
# 预提交检查
pre-commit run sqlfluff
现在你已经成为"SQL代码美容大师"!下一章我们将进入《SQL 性能监控与调优——给数据库装上"心电图仪"的硬核指南》的魔幻世界,记得给你的键盘准备按摩仪——优雅编码需要持之以恒! ♂️