为什么不在LEFT Join之后使用WHERE子句不会抛出任何异常?

时间:2016-06-23 09:11:24

标签: sql tsql

我最近注意到在使用LEFT JOIN时,如果您忘记使用WHERE子句,则不会收到任何错误消息,让您构建并运行它。但是WHERE子句之后的代码也不起作用。

检查此样本:

SELECT 
     [C].Id AS Id
    ,[C].Code AS Code
    ,[C].[Desc] AS [Desc]
    ,[C].DateCreated 
    ,[C].UserCreatedId, [U].Username AS UserCreatedUsername, '(' + [U].Username + ') ' + [U].Firstname + ' ' + [U].Lastname AS UserCreatedFirstnameLastname 

    FROM rel_MerchantCurrency [MC]
    LEFT JOIN Merchant [M] ON [MC].MerchantId = [M].Id
    LEFT JOIN Currency [C] ON [MC].CurrencyId = [C].Id
    LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id

    AND [M].Id = @MerchantId

    AND [MC].Deleted = 0
    AND [M].Deleted = 0
    AND [C].Deleted = 0
    AND [U].Deleted = 0

可以毫无问题地构建此代码。但是,它从不检查最后几行。所以它不能正常工作。但是这段代码如下:

 SELECT 
         [C].Id AS Id
        ,[C].Code AS Code
        ,[C].[Desc] AS [Desc]
        ,[C].DateCreated 
        ,[C].UserCreatedId, [U].Username AS UserCreatedUsername, '(' + [U].Username + ') ' + [U].Firstname + ' ' + [U].Lastname AS UserCreatedFirstnameLastname 

        FROM rel_MerchantCurrency [MC]
        LEFT JOIN Merchant [M] ON [MC].MerchantId = [M].Id
        LEFT JOIN Currency [C] ON [MC].CurrencyId = [C].Id
        LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id

        WHERE [M].Id = @MerchantId

        AND [MC].Deleted = 0
        AND [M].Deleted = 0
        AND [C].Deleted = 0
        AND [U].Deleted = 0

这很有效,因为我正在添加“WHERE”子句。

我的问题是:为什么我没有收到第一个代码的任何错误消息?我相信因为代码运行底部的所有AND子句与最后一个LEFT JOIN行。但是它不应该工作吗?你会建议避免这种情况,因为没有抛出异常?我最近更改了很多LEFT JOIN的存储过程,我认为大多数都存在这个问题,我不想再将它再次体验过。

2 个答案:

答案 0 :(得分:5)

在您的第一个查询中,它被解释为

LEFT JOIN [User] [U] 
   ON (
           [MC].UserCreatedId = [U].Id
       AND [M].Id = @MerchantId
       AND ...
      )

(注意括号)
这就是为什么忘记WHERE时语法错误的原因。您只需限制连接而不是最终结果。

答案 1 :(得分:3)

你的第一段代码在语法上是正确的,所以你不会得到错误,但它没有意义。由于您尚未使用WHERE子句,因此最后的所有ANDs都将应用于表[U]和[MC]之间的LEFT JOIN

您可能不知道,但是您可以将多个条件放入连接中,因此指定类似

的内容非常有效
LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id AND [MC].DateCreated = [U].DateCreated 

而不是

的等效陈述
LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id 
WHERE [MC].DateCreated = [U].DateCreated 

所以你的SQL基本上是指定

LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id
AND [M].Id = @MerchantId
AND [MC].Deleted = 0
AND [M].Deleted = 0
AND [C].Deleted = 0
AND [U].Deleted = 0 

由于您正在对与表[M]和[C]相关的连接应用条件,因此它们将被忽略,因为它们不会影响表[U]和[MC]之间的连接。并且因为它们被视为[U]和[MC]之间连接的条件,所以它们不适用于您想要的连接。

如果您愿意,可以将与已加入表相关的ANDs移动到联接中。这会使您的代码看起来像

SELECT 
     [C].Id AS Id
    ,[C].Code AS Code
    ,[C].[Desc] AS [Desc]
    ,[C].DateCreated 
    ,[C].UserCreatedId, [U].Username AS UserCreatedUsername, '(' + [U].Username + ') ' + [U].Firstname + ' ' + [U].Lastname AS UserCreatedFirstnameLastname 

    FROM rel_MerchantCurrency [MC]
    LEFT JOIN Merchant [M] ON [MC].MerchantId = [M].Id AND [M].Deleted = 0 AND [M].Id = @MerchantId
    LEFT JOIN Currency [C] ON [MC].CurrencyId = [C].Id AND [C].Deleted = 0
    LEFT JOIN [User] [U] ON [MC].UserCreatedId = [U].Id AND [U].Deleted = 0
    WHERE [MC].Deleted = 0