内连接(Inner Join),是关系型数据库中最基础也最常用的表连接方式之一。它的核心定义是:连接结果只包含那些完全满足连接条件的记录。
在 Oracle 数据库中,如何判断一个 SQL 是否是内连接呢?只要其 WHERE 子句中没有使用那些用于表示外连接的关键字即可。这些关键字包括:
- 标准 SQL 定义的:
LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN
- Oracle 自定义的:
(+) 操作符
如果没用到这些,那么该 SQL 的连接类型就是内连接。
一个内连接实例
为了更直观地理解,我们通过一个例子来演示。首先创建两个简单的测试表 T1 和 T2:
SQL> create table t1(col1 number,col2 varchar2(1));
Table created.
SQL> create table t2(col2 varchar2(1),col3 varchar2(2));
Table created.
然后,向两个表中各插入三条数据:
insert into t1 values(1,'A');
insert into t1 values(2,'B');
insert into t1 values(3,'C');
insert into t2 values('A','A2');
insert into t2 values('B','B2');
insert into t2 values('D','D2');
commit;
现在,表 T1 和 T2 中的数据如下:
SQL> select * from t1;
COL1 COL2
---------- -----
1 A
2 B
3 C
SQL> select * from t2;
COL2 COL3
----- -----
A A2
B B2
D D2
Oracle 中的传统内连接写法
来看一个最基本的内连接 SQL 示例(我们称它为 SQL 1):
select t1.col1, t1.col2, t2.col3 from t1, t2 where t1.col2 = t2.col2;
这条 SQL 没有使用任何外连接关键字,因此它是一个内连接,连接条件是 t1.col2 = t2.col2。让我们执行它:
SQL> select t1.col1, t1.col2, t2.col3 from t1, t2 where t1.col2 = t2.col2;
COL1 COL2 COL3
---------- ----- -----
1 A A2
2 B B2
从结果可以清晰看到内连接的特性:只有 T1 中 COL2 为 ‘A’ 和 ‘B’ 的记录,在 T2 中找到了匹配项(‘A’ 和 ‘B’),这两行才出现在结果集中。T1 中的 ‘C’ 和 T2 中的 ‘D’ 由于没有匹配项,均被排除在外。
标准 SQL 中的内连接写法
上面 SQL 1 的写法是 Oracle 早期支持的传统方式。而在 SQL92 标准中,内连接有更规范的语法,主要分为 JOIN ... ON 和 JOIN ... USING 两种。
1. JOIN ... ON
语法结构为:表1 JOIN 表2 ON (连接条件)。
将上面的例子用此语法重写(SQL 2):
select t1.col1, t1.col2, t2.col3 from t1 join t2 on (t1.col2 = t2.col2);
2. JOIN ... USING
语法结构为:表1 JOIN 表2 USING (连接列集合)。当有多个连接列时,列名之间用逗号分隔。
用此语法重写的例子(SQL 3):
select t1.col1, col2, t2.col3 from t1 join t2 using (col2);
执行 SQL 2 和 SQL 3,可以看到它们与 SQL 1 的结果完全一致:
SQL> select t1.col1, t1.col2, t2.col3 from t1 join t2 on (t1.col2 = t2.col2);
COL1 COL2 COL3
---------- ----- -----
1 A A2
2 B B2
SQL> select t1.col1, col2, t2.col3 from t1 join t2 using (col2);
COL1 COL2 COL3
---------- ----- -----
1 A A2
2 B B2
一个重要注意事项:当使用 JOIN ... USING 时,如果连接列也出现在了查询列列表中,则该列名前面不能加表名或别名,否则 Oracle 会报 ORA-25154 错误。
SQL> select t1.col1, t1.col2, t2.col3 from t1 join t2 using (col2);
select t1.col1, t1.col2, t2.col3 from t1 join t2 using (col2)
*
ERROR at line 1:
ORA-25154: column part of USING clause cannot have qualifier
这条 SQL 的错误在于第二个查询列写了 t1.col2,而 col2 是 USING 子句里的连接列,应直接写 col2。
需要警惕的 NATURAL JOIN
在标准 SQL 中,还有一种特殊的 JOIN ... USING 形式,叫做 NATURAL JOIN。它是一种更“自动化”的连接,其连接条件是两个表的所有同名列。
语法很简单:表1 NATURAL JOIN 表2。
这等价于:表1 JOIN 表2 USING (表1和表2的所有同名列集合)。
在我们的例子中,T1 和 T2 的同名列只有 COL2。因此,使用 NATURAL JOIN 的 SQL 4 与之前的 SQL 是等价的:
select t1.col1, col2, t2.col3 from t1 natural join t2;
执行结果也确实一致:
SQL> select t1.col1, col2, t2.col3 from t1 natural join t2;
COL1 COL2 COL3
---------- ----- -----
1 A A2
2 B B2
NATURAL JOIN 的好处显而易见——无需手动指定连接列,代码看起来更简洁。但它的缺点甚至风险更为突出:
- 隐含逻辑,易出错:连接条件由数据库自动推断,开发者可能忽略其背后是基于所有同名列这一事实。
- 列名相同,语义未必相同:两个表可能存在只是偶然同名的列(例如
T1 的 status 和 T2 的 status 可能表示完全不同的业务状态),它们不应该被用作连接条件,但 NATURAL JOIN 会将其自动纳入。
- 降低代码可维护性:当表结构发生变化(如新增一个同名列)时,
NATURAL JOIN 的行为可能会 silently 改变,导致难以排查的业务逻辑错误。
因此,在大多数生产环境和严谨的数据库开发中,并不推荐使用 NATURAL JOIN。明确使用 JOIN ... ON 写出清晰的连接条件,虽然多写几个字,但能极大地提升代码的可靠性、可读性和可维护性。这是一种更优的标准SQL实践。
理解内连接的不同写法及其细微差别,是进行高效、准确 SQL 编程的基础。希望本文的梳理能帮助你更好地掌握这一核心概念。如果你想深入探讨更多数据库优化技巧,欢迎来云栈社区交流分享。