在阅读它之后,这不是显式与隐式SQL连接的副本。 答案可能相关(甚至相同),但问题是不同的。


它们之间有什么不同?每一种都应该有什么不同?

如果我正确地理解了这个理论,那么查询优化器应该能够互换地使用这两种方法。


当前回答

关于你的问题,

只要你的服务器能得到它,内部连接的'on'和'where'都是一样的:

select * from a inner join b on a.c = b.c

and

select * from a inner join b where a.c = b.c

并非所有口译员都知道“where”选项,所以可能应该避免使用。当然,“on”从句更清楚。

其他回答

它们不是一回事。

考虑一下这些问题:

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345

and

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
    AND Orders.ID = 12345

第一个将返回订单及其行(如果有的话),订单号为12345。 第二个将返回所有订单,但只有订单12345有与之关联的行。

使用INNER JOIN,这两个子句实际上是等效的。然而,仅仅因为它们在功能上相同,产生相同的结果,并不意味着这两种子句具有相同的语义。

我认为这是连接序列效应。 在左上角连接的情况下,SQL先做左连接,然后做where过滤器。 在沮丧的情况下,找到订单。首先ID=12345,然后加入。

让我们考虑一下这些表格:

A

id | SomeData

B

id | id_A | SomeOtherData

id_A是表a的外键

写这个查询:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

将提供如下结果:

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

A中有而B中没有的东西意味着B中有空值。


现在,让我们考虑B.id_A中的一个特定部分,并从前面的结果中突出显示它:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

写这个查询:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

将提供如下结果:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

因为这将在内部连接中删除不在B.id_A = SpecificPart中的值


现在,让我们把查询改为这样:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

结果是:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

因为整个结果是根据B. id_a = SpecificPart过滤的,删除了B. id_a为NULL的部分,这些部分在A中,但不在B中

就优化器而言,使用ON或WHERE定义连接子句应该没有区别。

然而,恕我直言,我认为在执行连接时使用ON子句更清楚。这样,您就有了查询的特定部分,该部分规定了如何处理连接,而不是与其余WHERE子句混合。

对于内连接,它们的含义相同。但是,在外部连接中将得到不同的结果,这取决于您将连接条件放在WHERE子句中还是on子句中。看看这个相关的问题和答案(由我)。

我认为习惯总是把连接条件放在ON子句中是最有意义的(除非它是一个外部连接,而且你确实想把它放在where子句中),因为它使阅读你的查询的任何人都更清楚表是在什么条件下被连接的,而且它还有助于防止where子句长几十行。