lang
lang/sql/join/on-clause-required.md
medium
sql-on-clause-required
SQL 多表 JOIN 必带 ON 子句 — 缺 ON 会退化为笛卡尔积 / CROSS JOIN。Use when 写 SQL / 迁移脚本 / 评审涉及 `on-clause-required` 的 PR。
joinon多表条件
paths
**/*.sqlpy/**/*.pybackend/**/*.py
SQL · JOIN 必带 ON
规则
每个 JOIN 后必须跟 ON <连接条件>。
反例
-- ❌ JOIN 后无 ON(MySQL 会当成 CROSS JOIN)
SELECT *
FROM users u
JOIN presentations p
WHERE p.owner_id = u.id; -- WHERE 不是 ON
-- ❌ 用 WHERE 替代 ON(旧式语法)
SELECT *
FROM users u, presentations p
WHERE p.owner_id = u.id;
正例
-- ✅
SELECT u.name, p.title
FROM users u
INNER JOIN presentations p ON p.owner_id = u.id;
-- ✅ 多条件
INNER JOIN slides s
ON s.presentation_id = p.id
AND s.is_active = TRUE;
LEFT JOIN 注意点
-- ⚠️ LEFT JOIN 把过滤条件放 ON vs WHERE 含义不同
-- ON 上:保留左表全部行
SELECT u.name, p.title
FROM users u
LEFT JOIN presentations p ON p.owner_id = u.id AND p.is_active = TRUE;
-- WHERE 上:把 is_active=FALSE 的左表行也过滤掉,退化为 INNER JOIN
SELECT u.name, p.title
FROM users u
LEFT JOIN presentations p ON p.owner_id = u.id
WHERE p.is_active = TRUE;
按需选择,写 PR comment 说明意图。
Tortoise 中的等价
# Tortoise 自动生成正确的 ON
await Presentation.filter(owner__id=uid).prefetch_related("owner")
# 但 raw query 时仍要手写
自检
- [ ] 每个 JOIN 后跟 ON?
- [ ] LEFT JOIN 的过滤条件位置(ON vs WHERE)符合意图?
- [ ] 无逗号多表 FROM 写法?