我最近注意到在使用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的存储过程,我认为大多数都存在这个问题,我不想再将它再次体验过。
答案 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