了解 SQL 中的笛卡尔积

Understanding cartesian product in SQL

我无法理解笛卡尔积的工作原理。考虑简单的模式:

mysql> select * from account;
+----------------+-------------+---------+
| account_number | branch_name | balance |
+----------------+-------------+---------+
| A101           | Downtown    |     500 |
| A102           | Perryridge  |     400 |
| A201           | Brighton    |     900 |
| A215           | Mianus      |     700 |
| A217           | Brighton    |     750 |
| A222           | Redwood     |     700 |
| A305           | Round Hill  |     350 |
+----------------+-------------+---------+
7 rows in set (0.00 sec)

现在,当我提出查询时

select a.balance from account a, account b where a.balance<b.balance;

除了最大值 900,我得到了一系列值。然后使用 not in 运算符确定最大值。在此之前,在上述查询中,当根据条件 a.balance<b.balance 进行连接时,关系中的第一个元组必须是 500。理论上,前 5 个值必须是:

500
500
500
500
400

但我得到:

+---------+
| balance |
+---------+
|     400 |
|     350 |
|     350 |
|     500 |
|     400 |

效果如何?我正在使用 MySQL 数据库。

笛卡尔连接将第一个 table 中的每条记录与第二个 table 中的每条记录连接起来,因此由于您的 table 有 7 行并且它与自身连接,它应该return 49 条记录没有 where 子句。您的 where 子句只允许记录 a 的余额小于 b 的余额。正如您所说,900 是 table 中的最大余额,它永远不会小于任何其他余额,因此它永远不会被 returned。

关于前五行,SQL 的正常规则也适用于联接。由于 SQL table 没有内在顺序,因此完全由数据库决定如何 return 它们,除非您在 order by 子句中明确说明顺序。您列出的值是您希望查询 return 的完全有效值。

笛卡尔积从给定的两组数据中生成所有可能的记录组合。

在您的情况下,要生成笛卡尔积,您必须使用 CROSS JOIN:

SELECT 
  a.branch_name AS first_branch,
  b.branch_name AS second_branch,
  a.balance + b.balance AS total_balance
FROM account a
CROSS JOIN account b 

或者,使用 SQL:89 theta 样式连接:

SELECT 
  a.branch_name AS first_branch,
  b.branch_name AS second_branch,
  a.balance + b.balance AS total_balance
FROM account a, account b 

无论如何,笛卡尔积的目标是关联两个集合的所有行。

当您将一些过滤条件应用于 CROSS JOIN 生成的笛卡尔积时,结果将不再是笛卡尔积,而是它的一个子集,与给定的过滤条件相匹配。

因此,对于您的情况,此查询:

SELECT 
  a.balance 
FROM account a, account b 
WHERE a.balance < b.balance

不生成笛卡尔积。

事实上,一个比您的查询更好的替代方法是:

SELECT 
  a.balance 
FROM account a
WHERE a.balance < (
  SELECT MAX(balance) FROM account 
)

如果要获取余额低于最大值的所有行。

无论如何,这里使用 self CROSS JOIN 看起来很可疑。这就是为什么您最好改用子查询的原因。