SQL-92的WHERE连接需拆为JOIN+ON,关联条件(如s.class_num=c.class_num)移入ON,非关联过滤条件(如s.sex='男')保留在WHERE;外连接迁移时注意(+)位置对应LEFT/RIGHT方向,避免语义错误。

SQL-92 的 WHERE 连接写法必须拆成 JOIN + ON
SQL-92 把所有逻辑塞进 WHERE,比如 SELECT s.name, c.class_name FROM student s, class c WHERE s.class_num = c.class_num AND s.sex = '男'。这种写法在多表时极易混淆连接条件和业务筛选条件。迁移时第一步就是识别出哪些 = 是表间关联(即外键/主键匹配),把它们拎出来作为 ON 子句;其余过滤条件(如 s.sex = '男')保留在 WHERE 中。
常见错误是把所有条件都挪到 ON 里,导致外连接语义错乱——比如 LEFT JOIN ... ON x=y AND z='a' 会让右表的 z='a' 变成连接前提,而不是最终结果过滤,实际效果等同于内连接。
- 只提取关联字段对:如
s.class_num = c.class_num、e.deptno = d.deptno - 非关联条件(
WHERE原有内容中不含=表间字段的)一律留在WHERE - 多个表时,每对关联都要独立写
ON,不能合并成一个大条件
外连接从 (+) 迁移到 LEFT/RIGHT JOIN 要注意方向反转
Oracle 风格的 SQL-92 外连接用 (+) 标记从表,比如 WHERE a.id = b.id(+) 表示 b 是从表、a 是主表,对应 SQL-99 的 LEFT JOIN(以 a 为主)。但新手常误以为 (+) 在右边就该写 RIGHT JOIN,其实相反:(+) 出现在哪边,哪边就是被补 NULL 的从表,也就是 JOIN 关键字左边那个表是主表。
MySQL 用户不用操心这个,因为 MySQL 从不支持 (+) 语法;但如果你正从 Oracle 迁移旧脚本,这点必须人工核对,否则查询结果会漏数据或补错 NULL。
-
a.x = b.y(+)→a LEFT JOIN b ON a.x = b.y -
a.x(+) = b.y→a RIGHT JOIN b ON a.x = b.y,等价于b LEFT JOIN a ON a.x = b.y - 全外连接在 MySQL 中不存在,需用
LEFT JOIN+RIGHT JOIN+UNION拼接
INNER JOIN 的 inner 关键字可以安全省略
SQL-99 允许写 FROM t1 JOIN t2 ON ...,省略 INNER。几乎所有主流数据库(MySQL、PostgreSQL、SQL Server、Oracle)都支持,且语义完全等价。没必要为了“显式”而硬加 INNER,反而增加冗余。
但要注意:单独写 JOIN 必须带 ON(Oracle 严格要求,MySQL 宽松但不推荐省略)。如果漏掉 ON,MySQL 会当作隐式 CROSS JOIN,立刻触发笛卡尔积——数据量稍大就卡死或爆内存。
- ✅ 推荐:
SELECT * FROM orders JOIN customers ON orders.cid = customers.id - ❌ 危险:
SELECT * FROM orders JOIN customers(无ON,等价于CROSS JOIN) - ⚠️ Oracle 会直接报错,MySQL 不报错但结果不可控
别名和字段歧义问题在 SQL-99 中更易暴露
SQL-92 因为所有表都在 FROM 后用逗号列出来,字段来源有时靠上下文猜;SQL-99 的 JOIN 链式结构让表作用域更清晰,但也意味着字段引用一旦没加别名,数据库更容易报 Column 'xxx' in field list is ambiguous 错误。
这不是语法缺陷,而是提示你:该明确限定字段归属了。尤其当多表有同名列(如 id、name)时,必须用 t1.id 或 s.name 显式声明,不能依赖顺序或默认解析。
- 所有 SELECT 列、WHERE 条件、ORDER BY 字段,只要涉及多表,优先加表别名前缀
- 避免使用
SELECT *—— 它在 JOIN 场景下既低效又容易引发歧义 - 如果用到了子查询或 CTE,别名冲突风险更高,务必逐层检查
迁移不是改几个关键字的事。最常被忽略的是连接条件与过滤条件的语义分离,以及外连接方向在不同语法下的映射关系。哪怕只改一行 SQL,也要确认 ON 里没塞业务逻辑、(+) 翻译后主从关系没颠倒、字段引用没有裸奔。

















