了解SQL中的笛卡尔积

时间:2015-06-20 14:55:38

标签: mysql sql select join cartesian-product

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

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数据库。

2 个答案:

答案 0 :(得分:3)

笛卡尔连接将第一个表中的每个记录与第二个表中的每个记录连接起来,因此,由于您的表有7行并且它与自身连接,如果没有{{{},它应该返回49个记录1}}子句。您的where子句仅允许where的余额小于a余额的记录。正如你所说,b是表中的最大余额,它永远不会小于任何其他余额,因此永远不会返回。

关于前五行,SQL的常规规则也适用于连接。由于SQL表没有内在顺序,因此完全由数据库决定如何返回它们,除非您在900子句中明确说明了一个顺序。您列出的值是完全有效的值,您希望查询返回。

答案 1 :(得分:0)

正如我在this article中所解释的那样,笛卡尔乘积可以从两组给定的数据集中生成所有可能的记录组合。

对于您的情况,要生成笛卡尔积,您必须使用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看起来很可疑。这就是为什么您最好改用子查询。