🙏 感谢您的支持! 我们在七月份已经筹集了 $65 — 这足够我们工作到下个月。请帮助我们保持进度,进一步支持这个项目。 支持这个项目 →
SQL 代码已复制到剪贴板

课程 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 子句(没有匹配条件)。
  • 结果中的行数是两个表行数的 乘积
  • 在大型数据集上谨慎使用,以避免性能问题。