JOIN 子句

最近更新时间:2026-05-06 16:28:13

我的收藏
JOIN 子句是 SELECT 语句的核心,用于将两个或多个表的数据基于相关标识符(如外键)组合在一起,实现跨表数据的交叉引用。

语法概览与连接类型

TCHouse-X 支持多种标准的 SQL 连接方式:
基本连接:INNER JOIN (默认), LEFT [OUTER] JOIN, RIGHT [OUTER] JOIN, FULL [OUTER] JOIN
高级连接:
SEMI JOIN:半连接(左/右),仅返回在一侧表中存在匹配的行,且每行仅返回一次。
ANTI JOIN:反连接,返回在一侧表中找不到匹配项的行。
笛卡尔积:CROSS JOIN 或不带 ON 条件的 JOIN
SELECT select_list FROM
table_or_subquery1 [INNER] JOIN table_or_subquery2 |
table_or_subquery1 {LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER]} JOIN table_or_subquery2 |
table_or_subquery1 {LEFT | RIGHT} SEMI JOIN table_or_subquery2 |
table_or_subquery1 {LEFT | RIGHT} ANTI JOIN table_or_subquery2 |
[ ON col1 = col2 [AND col3 = col4 ...] |
USING (col1 [, col2 ...]) ]
[other_join_clause ...]
[ WHERE where_clauses ]

SELECT select_list FROM
table_or_subquery1, table_or_subquery2 [, table_or_subquery3 ...]
[other_join_clause ...]
WHERE
col1 = col2 [AND col3 = col4 ...]

SELECT select_list FROM
table_or_subquery1 CROSS JOIN table_or_subquery2
[other_join_clause ...]
[ WHERE where_clauses ]

连接风格:SQL-92 vs. SQL-89

SQL-92 (推荐)

使用显式的 JOIN 关键字,逻辑清晰,易于维护。
ON 子句:用于不同名列的比较。
USING 子句:当两表连接列名相同时的简写(如 USING (id))。
-- 使用 ON
SELECT t1.c1, t2.c2 FROM t1 JOIN t2 ON t1.id = t2.id;
-- 使用 USING
SELECT t1.c1, t2.c2 FROM t1 JOIN t2 USING (id);

SQL-89 (传统)

使用逗号分隔表名,连接条件置于 WHERE 中。
风险:若误删 WHERE 中的连接条件,会意外产生巨大的笛卡尔积。
限制:TCHouse-X 的外连接(OUTER JOIN)必须使用 SQL-92 语法,不支持 (+) *=

通用连接场景

在 TCHouse-X 中,通用连接场景主要分为内连接(INNER JOIN)和外连接(OUTER JOIN),它们决定了如何处理两表中不匹配的数据。

内连接 (Inner Join)

内连接是最常用的连接类型。它仅返回两个表中连接列值完全匹配的行组合。
默认行为:TCHouse-X 默认执行内连接。
命名冲突:若两表存在同名列,必须使用表前缀(如 t1.id)或别名来消除歧义。
语法等价性:以下三种写法在 TCHouse-X 中效果相同。
-- 1. SQL-89 风格(隐含连接)
SELECT t1.id, c1, c2 FROM t1, t2 WHERE t1.id = t2.id;

-- 2. SQL-92 风格(显式连接)
SELECT t1.id, c1, c2 FROM t1 JOIN t2 ON t1.id = t2.id;

-- 3. 显式内连接(语义最清晰)
SELECT t1.id, c1, c2 FROM t1 INNER JOIN t2 ON t1.id = t2.id;

外连接 (Outer Join)

外连接用于保留不满足连接条件的行。当一侧表没有匹配数据时,结果集中对应的另一侧列将填充为 NULL
左外连接 (LEFT OUTER JOIN):返回左表所有行。右表无匹配则补 NULL
右外连接 (RIGHT OUTER JOIN):返回右表所有行。左表无匹配则补 NULL
全外连接 (FULL OUTER JOIN):返回左、右表中的所有行。任何一侧缺失匹配均补 NULL
-- 左外连接
SELECT * FROM t1 LEFT OUTER JOIN t2 ON t1.id = t2.id;

-- 右外连接
SELECT * FROM t1 RIGHT OUTER JOIN t2 ON t1.id = t2.id;

-- 全外连接
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;
警告:
强制风格:执行外连接时,TCHouse-X 必须使用 SQL-92 语法(即 JOIN 关键字)。不支持通过逗号分隔表名的方式实现外连接。
不支持扩展符号:TCHouse-X 不支持某些传统数据库(如 Oracle 或 SQL Server 老版本)中的厂商专用扩展符,如 (+)*=

特殊连接场景

自连接 (Self-joins)

用于处理树形结构(如父子关系)。通过为同一张表分配不同的别名实现。
SELECT lhs.id AS child, rhs.id AS parent
FROM tree_data lhs, tree_data rhs
WHERE lhs.parent_id = rhs.id;

等值与非等值连接

等值连接 (Equijoins):使用 = 比较。这是最高效的连接方式,支持哈希连接(Hash Join)。
非等值连接 (Non-Equijoins):使用 !=, <, > 等。
警告:
非等值连接通常通过 CROSS JOIN 配合 WHERE 实现,或在 OUTER JOIN 中使用。由于涉及嵌套循环连接(Nested Loop Join),可能非常耗费内存且不支持溢写磁盘。

半连接 (Semi-joins)

半连接是一种高效的关联变体,主要用于判断“存在性”。它与普通内连接(Inner Join)最大的区别在于:即使右表中有多个匹配项,左表的每一行也只会被返回一次。这有效地避免了结果集的冗余膨胀。
核心特性
左半连接 (LEFT SEMI JOIN):仅当右表中存在匹配数据时,才返回左表的记录。
右半连接 (RIGHT SEMI JOIN):反转比较逻辑,仅返回右表中有匹配项的记录(TCHouse-X 2.2 及更高版本支持)。
去重机制:半连接在逻辑上等价于 EXISTS 子句。它不会合并右表的列到结果集中,只返回原始表的数据。
示例:左半连接 (LEFT SEMI JOIN)
以下查询将检索出所有“在表 t2 中拥有匹配 ID”的 t1 记录:
-- 仅返回 t1 的列,且 t1 的每一行在结果集中最多出现一次
SELECT t1.c1, t1.c2
FROM t1 LEFT SEMI JOIN t2
ON t1.id = t2.id;
半连接与内连接对比:
特性
内连接 (INNER JOIN)
半连接 (SEMI JOIN)
结果集大小
可能因为右表的多条匹配产生笛卡尔积
绝不产生重复行,保持左表原有的行数或更少
返回列
包含左右两表的所有请求列
仅包含单侧表的列
典型场景
获取两个表的组合信息
检查数据是否存在(类似 INEXISTS

自然连接 (Natural Joins)

自然连接是一种特殊的等值连接,它通过隐式匹配两个表中所有名称相同的列来建立关联。
工作原理
自动匹配:自然连接会自动寻找左表和右表中命名的所有列,并执行等值比较,无需手动编写 ONUSING 子句。
列去重:在结果集中,同名的连接列仅会保留一份(虽然在 SELECT * 时表现明显,但在指定列名查询时需注意别名使用)。
语法样例
-- 假设 t1 和 t2 都有名为 'id' 和 'type' 的列
-- 系统会自动执行 ON t1.id = t2.id AND t1.type = t2.type
SELECT t1.c1, t2.c2
FROM t1 NATURAL JOIN t2;
警告:
尽管 NATURAL JOIN 简化了代码,但在生产环境中需谨慎使用:
结构依赖性强:查询结果高度依赖于表结构。如果未来在其中一个表中添加了与另一表同名的无关列,连接条件会意外增加,导致结果集大幅缩小或为空。
维护成本高:TCHouse-X 场景,数据模型演进较快。列名的微小变动可能会导致下游报表或逻辑发生不可预知的变化。
可读性较差:对于不熟悉表结构的维护者来说,仅通过 SQL 语句很难直观判断连接的具体字段。

反连接 (Anti-joins)

反连接(Anti-join)是半连接的逻辑反面。它用于筛选出那些在另一张表中找不到匹配项的记录。这在查找“孤立数据”或执行“排除逻辑”时非常高效。
核心特性
左反连接 (LEFT ANTI JOIN):返回左表中所有与右表不匹配的行。
负向逻辑:它表达的是“不存在”的关系,即:返回所有在右表中没有对应关联键的左表记录。
版本支持:TCHouse-X 目前全面支持 LEFT ANTI JOINRIGHT ANTI JOIN 目前尚不支持,计划在后续版本中推出。
语法示例
以下查询将返回所有在 t2 表中没有对应项的 t1 记录:
SELECT t1.id, t1.c1
FROM t1 LEFT ANTI JOIN t2
ON t1.id = t2.id;

NULL 值的连接处理

默认情况下 NULL = NULL 为假。
说明:
使用 <=>(NULL-Safe Equal)操作符。它比 OR (A IS NULL AND B IS NULL) 更简洁且性能更高,因为它能利用哈希连接。

性能调优

连接查询是资源密集型操作,优化顺序至关重要。

强制顺序控制

STRAIGHT_JOIN紧跟 SELECT 关键字,强制按 FROM 子句中的表顺序执行连接。
SELECT STRAIGHT_JOIN t1.id, t1.c1, t2.c2
FROM t1 JOIN t2
ON t1.id = t2.id;
LEADING Hint:在复杂查询中精确指定顺序。
SELECT /*+ LEADING(t1 t2 t3) */ ... FROM t1 JOIN t2 ... JOIN t3 ...

统计信息与 CBO

TCHouse-X 的自研优化器 (Horn) 依赖统计信息进行 基于成本的优化 (CBO)。
统计信息维护命令
查看:SHOW TABLE STATS [table_name]
收集:COMPUTE STATS [table_name] (非分区) 或 COMPUTE INCREMENTAL STATS (分区表)。
手动策略(无统计信息时)
1. 先连接最大的表。
2. 优先连接过滤性(返回行数最少)的表。