下面的两个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'更改了。感谢到目前为止的所有回复。
答案 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)
答案 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。
可以将INNER JOIN语句重写为具有WHERE子句的CROSS JOIN,该WHERE子句与您在INNER JOIN查询的ON子句中使用的条件相同。
考虑到我们有以下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 JOIN子句允许您关联属于不同表的行。例如,CROSS JOIN将创建一个笛卡尔积,其中包含两个联接表之间所有可能的行组合。
尽管CROSS JOIN在某些情况下很有用,但在大多数情况下,您希望根据特定条件连接表。而且,这就是INNER JOIN发挥作用的地方。
SQL INNER JOIN允许我们根据通过ON子句指定的条件来过滤联接两个表的笛卡尔积。
如果提供“始终为真”的条件,则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
我们将获得post
和post_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
另一方面,如果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
最常见的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。