课程 5.6: CROSS JOIN - 笛卡尔积
虽然大多数连接需要特定的匹配条件(ON 子句),但 CROSS JOIN 是不同的。它返回连接表中每种可能的行组合。这个结果在数学上被称为 笛卡尔积。
什么是 CROSS JOIN?
CROSS JOIN 生成一个结果集,其中行数是第一个表中的行数与第二个表中的行数相乘的结果。没有条件用于匹配行;表 A 中的每一行都与表 B 中的每一行相匹配。
可视化:
表 A (颜色) 表 B (尺寸)
+-----------+ +-----------+
| 颜色 | | 尺寸 |
+-----------+ +-----------+
| 红色 | --\ | 小号 |
| 蓝色 | ---|------> | 中号 |
+-----------+ --/ | 大号 |
+-----------+
结果 (组合):
红色, 小号
红色, 中号
红色, 大号
蓝色, 小号
蓝色, 中号
蓝色, 大号
如果表 A 有 2 行,表 B 有 3 行,则结果将有 2 x 3 = 6 行。
CROSS JOIN 语法
有两种方式来编写笛卡尔积:
-- 显式语法
SELECT
table1.column,
table2.column
FROM
table1
CROSS JOIN
table2;
-- 隐式逗号语法
SELECT
table1.column,
table2.column
FROM
table1,
table2;
理解这些形式不仅在风格上不同,而且在运算符优先级上也不同是很重要的。
- 显式
JOIN的优先级更高,并且与查询文本中的其他JOIN子句按相同顺序处理。 - 逗号语法的优先级较低,实际上仅在显式
JOIN之后处理。
因此,在同一个 FROM 子句中混合逗号连接和显式 JOIN 可能会改变查询的含义,甚至导致错误。
例如,以下查询是无效的:
FROM a, b JOIN c ON (a.x = c.y AND b.z = c.t)
为什么这是一个错误:
- 首先,显式的
b JOIN c被处理; - 此时,表
a尚未在该连接表达式的范围内; - 因此,在
ON子句中对a.x的引用是无效的。
这就是为什么显式的 CROSS JOIN 通常更可取:不仅因为它看起来更清晰,而且因为它与其他 JOIN 更加契合,避免了隐藏的优先级问题。
警告: 在大型表上使用
CROSS JOIN时要非常小心。连接两个各有 1,000 行的表将产生 1,000,000 行!
实际示例(Sakila 数据库)
1. 生成所有可能的组合
假设我们想创建一个报告或网格,显示每个商店的每个电影类别,即使该商店当前没有该类别的电影。
SELECT
s.store_id,
c.name AS category_name
FROM
store AS s
CROSS JOIN
category AS c;
这将生成商店 1 的所有类别列表,随后是商店 2 的所有类别。
2. 创建测试数据或矩阵
CROSS JOIN 通常用于生成大量的排列组合,用于测试或构建日历/时间表,在这些情况下需要查看所有时间段与所有用户的对应关系。
何时使用 CROSS JOIN
- 生成排列组合: 当你需要每种可能组合的列表时(例如,所有产品颜色与所有产品尺寸)。
- 填补空白: 与
LEFT JOIN一起使用时,可以帮助识别数据中缺失的组合。 - 报告: 创建必须包含所有类别的报告“骨架”,即使那些值为零的类别。
本课的关键要点
- CROSS JOIN 返回两个表的 笛卡尔积。
- 它不使用
ON子句(没有匹配条件)。 - 结果中的行数是两个表行数的 乘积。
- 在大型数据集上谨慎使用,以避免性能问题。