了解 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
看起来很可疑。这就是为什么您最好改用子查询的原因。
我无法理解笛卡尔积的工作原理。考虑简单的模式:
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
看起来很可疑。这就是为什么您最好改用子查询的原因。