28

下面的两位 SQL 得到相同的结果

SELECT c.name, o.product  
FROM customer c, order o  
WHERE c.id = o.cust_id  
AND o.value = 150  

SELECT c.name, o.product  
FROM customer c  
INNER JOIN order o on c.id = o.cust_id  
WHERE o.value = 150

我已经看到这两种风格在不同的公司都被用作标准。据我所见,第二个是大多数人在网上推荐的。除了风格之外,还有什么真正的原因吗?使用 Inner Join 有时会有更好的性能吗?

我注意到 Ingres 和 Oracle 开发人员倾向于使用第一种风格,而 Microsoft SQL Server 用户倾向于使用第二种风格,但这可能只是巧合。

感谢您的任何见解,我一直想知道这个问题。

编辑:由于我使用了不正确的术语,我已将标题从“SQL 内连接与笛卡尔积”更改。感谢您迄今为止的所有回复。

4

7 回答 7

28

这两个查询都是内部连接和等价的。第一种是较老的做事方法,而 JOIN 语法的使用只是在引入 SQL-92 标准之后才变得普遍(我相信它在较旧的定义中,只是在那之前并没有特别广泛地使用)。

强烈推荐使用 JOIN 语法,因为它将连接逻辑与 WHERE 子句中的过滤逻辑分开。虽然 JOIN 语法实际上是内连接的语法糖,但它的优势在于外连接,旧的 * 语法可能会产生无法明确描述连接并且解释依赖于实现的情况。[左 | RIGHT] JOIN 语法避免了这些陷阱,因此为了保持一致性,在所有情况下都最好使用 JOIN 子句。

请注意,这两个示例都不是笛卡尔积。为此,您可以使用

SELECT c.name, o.product  
FROM customer c, order o  
WHERE o.value = 150  

或者

SELECT c.name, o.product  
FROM customer c  CROSS JOIN order o 
WHERE o.value = 150
于 2008-12-27T10:38:15.877 回答
6

为了回答您的部分问题,我认为 Oracle 中 JOIN ... ON 语法中的早期错误阻止了 Oracle 用户远离该语法。我不认为现在有什么特别的问题。

它们是等价的,应该被解析为相同的内部表示以进行优化。

于 2008-12-27T10:19:58.317 回答
4

实际上这些例子是等价的,也不是笛卡尔积。连接两个表而不指定连接条件时返回笛卡尔积,例如

select *
from t1,t2

在Wikipedia上有很好的讨论。

于 2008-12-27T10:17:07.463 回答
4

Oracle 在支持 JOIN ... ON (ANSI) 语法方面很晚(直到 Oracle 9),这就是 Oracle 开发人员经常不使用它的原因。

就个人而言,我更喜欢使用 ANSI 语法,因为逻辑上很清楚一个表正在驱动查询,而其他表是查找表。当表格“相等”时,我倾向于使用笛卡尔语法。

性能应该完全不同。

于 2008-12-27T10:24:30.523 回答
3

两个查询都在执行内部连接,只是语法不同。

于 2008-12-27T10:17:03.173 回答
3

JOIN... ON... 语法是对 SQL 的 ANSI 和 ISO 规范的最新补充。JOIN... ON... 语法通常是首选,因为它 1) 将连接条件从 WHERE 子句中移出,使得 WHERE 子句仅用于过滤;2) 如果您正在创建一个可怕的笛卡尔积,则它会更加明显,因为每个JOIN 必须伴随至少一个 ON 子句。如果所有的连接条件都只是在 WHERE 子句中进行了 AND 运算,那么当缺少一个或多个条件时就不那么明显了。

于 2008-12-29T00:23:49.813 回答
2

TL;博士

INNER JOIN 语句可以重写为 CROSS JOIN,其 WHERE 子句与您在 INNER JOIN 查询的 ON 子句中使用的条件匹配。

表关系

考虑到我们有以下postpost_comment表格:

post 和 post_comment 表

有以下post记录:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

并且post_comment具有以下三行:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL 内连接

SQL JOIN 子句允许您关联属于不同表的行。例如,CROSS JOIN将创建一个笛卡尔积,其中包含两个连接表之间所有可能的行组合。

虽然 CROSS JOIN 在某些情况下很有用,但大多数时候,您希望根据特定条件连接表。而且,这就是 INNER JOIN 发挥作用的地方。

SQL INNER JOIN 允许我们根据通过 ON 子句指定的条件过滤连接两个表的笛卡尔积。

SQL INNER JOIN - 在“始终为真”条件下

如果您提供“始终为真”条件,则 INNER JOIN 不会过滤连接的记录,结果集将包含两个连接表的笛卡尔积。

例如,如果我们执行以下 SQL INNER JOIN 查询:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

我们将得到所有的组合postpost_comment记录:

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

因此,如果 ON 子句条件为“始终为真”,则 INNER JOIN 就等同于 CROSS JOIN 查询:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER JOIN - ON“总是假”条件

另一方面,如果 ON 子句条件为“始终为假”,则所有连接的记录都将被过滤掉,结果集将为空。

因此,如果我们执行以下 SQL INNER JOIN 查询:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

我们不会得到任何结果:

| p.id    | pc.id      |
|---------|------------|

这是因为上面的查询等价于下面的 CROSS JOIN 查询:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

SQL INNER JOIN - 使用外键和主键列的 ON 子句

最常见的 ON 子句条件是子表中的外键列与父表中的主键列匹配的条件,如以下查询所示:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

在执行上述 SQL INNER JOIN 查询时,我们得到以下结果集:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

因此,只有符合 ON 子句条件的记录才会包含在查询结果集中。在我们的例子中,结果集包含所有post以及它们的post_comment记录。post没有关联的行post_comment被排除,因为它们不能满足 ON 子句条件。

同样,上面的 SQL INNER JOIN 查询等价于下面的 CROSS JOIN 查询:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

未命中的行是满足 WHERE 子句的行,只有这些记录才会包含在结果集中。这是可视化 INNER JOIN 子句如何工作的最佳方式。

| p.id | pc.post_id | pc.id | p.title | 电脑评论 |
|--------|------------|--------|-----------|--------- --|
| 1 | 1 | 1 | 爪哇 | 好 |
| 1 | 1 | 2 | 爪哇 | 优秀 |
| 1 | 2 | 3 | 爪哇 | 真棒| 
| 2 | 1 | 1 | 休眠 | 好 | 
| 2 | 1 | 2 | 休眠 | 优秀 |
| 2 | 2 | 3 | 休眠 | 真棒|
| 3 | 1 | 1 | JPA | 好 | 
| 3 | 1 | 2 | JPA | 优秀 | 
| 3 | 2 | 3 | JPA | 真棒|

并不是说这仅适用于 INNER JOIN,不适用于 OUTER JOIN。

于 2020-04-07T19:03:57.053 回答