SQL内部连接语法

时间:2008-12-27 10:14:15

标签: sql

下面的两个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

我已经看到两种风格在不同的公司都被用作标准。从我所看到的,第二个是大多数人在网上推荐的。除了风格之外,还有其他真正的理由吗?使用内部联接有时会有更好的表现吗?

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

感谢您的任何见解,我一直想知道这件事。

编辑:因为我使用的是不正确的terminlogy,所以我已经将标题从'SQL Inner Join与Cartesian Product'更改了。感谢到目前为止的所有回复。

7 个答案:

答案 0 :(得分:27)

两个查询都是内部联接和等效的。第一种是较旧的处理方法,而JOIN语法的使用仅在引入SQL-92标准后才变得普遍(我相信它在较旧的定义中,在此之前并没有特别广泛使用)。 / p>

强烈建议使用JOIN语法,因为它将连接逻辑与WHERE子句中的过滤逻辑分开。虽然JOIN语法实际上是内连接的语法糖,但它的优势在于外连接,其中旧的*语法可以产生无法明确描述连接并且解释依赖于实现的情况。 [LEFT |正确] 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

答案 1 :(得分:6)

为了回答你的部分问题,我认为Oracle中JOIN ... ON语法的早期错误使得Oracle用户不再使用该语法。我认为现在没有任何特别的问题。

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

答案 2 :(得分:4)

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

select *
from t1,t2

Wikipedia对此进行了很好的讨论。

答案 3 :(得分:4)

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

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

表现应该完全不同。

答案 4 :(得分:3)

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

答案 5 :(得分:3)

JOIN ... ON ...语法是SQL的ANSI和ISO规范的最新版本。 JOIN ... ON ...语法通常是首选的,因为它1)将连接条件移出WHERE子句,使WHERE子句仅用于过滤,2)如果你创建一个可怕的笛卡尔积,则更明显JOIN必须至少包含一个ON子句。如果WHERE子句中的所有连接条件都只是AND,那么当缺少一个或多个时,它就不那么明显了。

答案 6 :(得分:2)

这是一个非常常见的问题,因此此答案基于我写的this article

TL; DR

可以将INNER JOIN语句重写为具有WHERE子句的CROSS JOIN,该WHERE子句与您在INNER JOIN查询的ON子句中使用的条件相同。

表关系

考虑到我们有以下postpost_comment表:

The <code>post</code> and <code>post_comment</code> tables

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子句条件为“始终为true”,则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子句条件为“始终为false”,则所有联接的记录都将被过滤掉,结果集将为空。

因此,如果我们执行以下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子句条件是将子表中的Foreign Key列与父表中的Primary Key列匹配的条件,如以下查询所示:

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的{​​{1}}行被排除,因为它们不满足ON子句条件。

同样,上述SQL INNER JOIN查询等同于以下CROSS JOIN查询:

post_comment

未删除的行是满足WHERE子句的行,并且仅这些记录将包含在结果集中。这是可视化INNER JOIN子句工作方式的最佳方法。

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

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