SQL表别名须用AS显式声明且具业务语义,如usr/ord;JOIN条件需垂直对齐、ON独行缩进;SELECT字段必带表前缀;CTE命名要表达意图,仅在必要时展开。

表别名必须用 AS 显式声明,且命名要有语义
很多人图省事写 SELECT * FROM users u, orders o,这种隐式别名在复杂查询里极易混淆,尤其当多层嵌套或 UNION 时,连自己都认不出 u 到底指哪个 users(比如有 users_backup 或 user_profiles)。显式 AS 是可读性的底线。
- 别名优先用业务缩写而非字母序:用
AS usr而不是AS u,AS ord而不是AS o - 若涉及同一张表多次关联(如查用户及其推荐人),必须加区分后缀:
users AS usr和users AS referrer - 避免单字母、下划线开头、数字开头等易误读的别名:
AS _u、AS u1、AS 2024_users全部不推荐
JOIN 条件必须垂直对齐,ON 子句单独成行
把所有 ON 条件堆在一行,比如 ON u.id = o.user_id AND u.status = 'active' AND o.created_at > '2024-01-01',一眼看不出主外键关系,也难定位漏加条件的位置。SQL 不是 Python,缩进不靠空格数量,而靠结构分层。
-
JOIN关键字后换行,ON单独起一行并缩进两个空格 - 多个条件用
AND拆开,每行一个,对齐=或IN等操作符 - 外键关联优先写在最上面,业务过滤条件往下排——这样扫一眼就能确认关联是否正确
SELECT usr.name, ord.total FROM users AS usr JOIN orders AS ord ON usr.id = ord.user_id AND ord.status = 'paid' AND ord.created_at >= '2024-01-01'
SELECT 字段必须带表别名前缀,禁止裸字段
一旦两个表有同名字段(比如 id、created_at),不加前缀的 SELECT id, name 会直接报错或返回意外结果。更隐蔽的问题是:字段来源模糊,后续加表或改逻辑时,没人敢动这行 SELECT。
- 所有字段必须写成
usr.id、ord.created_at形式,即使当前只有一张表也要养成习惯 - 聚合字段或计算字段需另起别名:
COUNT(*) AS total_orders,避免和原始字段名冲突 - 别依赖 IDE 的自动补全来“猜”字段归属——它不会告诉你这个
status到底来自users还是orders
子查询和 CTE 必须命名清晰,且只在必要时展开
把三层嵌套子查询塞进 FROM 里,还起名叫 t1、t2,等于主动放弃可维护性。但反过来,为一个简单过滤硬套 WITH 也增加认知负担。关键在“必要时”。
- CTE 名称要表达意图:
WITH active_users AS (…)比WITH t1 AS (…)强十倍 - 子查询仅在需要复用、或逻辑块边界明确(如“统计每个用户的订单数”)时才提取为 CTE
- 如果 CTE 只被引用一次,且不到 5 行,直接内联反而更直观;反之,超过 8 行或含
GROUP BY/WINDOW就该拆
字段前缀、ON 对齐、CTE 命名这些事,看起来只是“写得整齐点”,实际影响的是下次你 or 别人 debug 时,能不能在 30 秒内定位到 JOIN 漏了条件,或者发现 status 其实来自错误的表。可读性不是风格问题,是调试成本问题。

















