我有两张桌子(tblReps和tblDailyWorkingTime)。该tblReps表,即第一个,返回 37 行,但是当我将它与第二个表连接时,我得到 36 行,因为第二个表只有 36 行与第一个表匹配。
如何使用不匹配的行的 NULL 结果返回 37 行?
这是我到目前为止的查询:
SELECT
tblReps.[sName] AS 'RepName',
tblReps.sNote AS 'Type',
RIGHT(CAST(tblDaily.sDateAndTimeStart AS smalldatetime), 8) AS 'DayStarted'
FROM
[tblRepresentatives] AS tblReps
FULL OUTER JOIN
tblDailyWorkingTime AS tblDaily ON tblDaily.sRepresentativeCode = tblReps.sCode
WHERE
tblDaily.sDate = CAST(GETDATE() AS DATE)
AND tblReps.[sActive] = 'True'
Run Code Online (Sandbox Code Playgroud)
首先,在这种情况下使用的正确连接类型是左连接:
...
FROM
[tblRepresentatives] AS tblReps
LEFT OUTER JOIN
tblDailyWorkingTime AS tblDaily ON tblDaily.sRepresentativeCode = tblReps.sCode
...
Run Code Online (Sandbox Code Playgroud)
在您的特定情况下,您仍然可以使用,FULL因为WHERE无论如何这个条件都会将其变成左连接:
tblReps.[sActive] = 'True'
Run Code Online (Sandbox Code Playgroud)
但最好能准确表达意图。
将您的完全连接变成左连接的相同效果实际上是造成您预期的第 37 行丢失的原因。更具体地说,这个其他WHERE条件:
tblDaily.sDate = CAST(GETDATE() AS DATE)
Run Code Online (Sandbox Code Playgroud)
将您的 join 进一步转换为内部 join。这就是输出中缺少第 37 行的原因。
发生这种情况的原因是这样的。该FROM子句tblDaily.sDate为不匹配的行返回空值。由于该WHERE条款逻辑执行后的FROM,上述断言排除不匹配的行,因为NULL = CAST(GETDATE() AS DATE)不会评估为True。
您需要做的是将sDate条件移至ON子条款:
...
FROM
[tblRepresentatives] AS tblReps
LEFT OUTER JOIN
tblDailyWorkingTime AS tblDaily ON tblDaily.sRepresentativeCode = tblReps.sCode
AND tblDaily.sDate = CAST(GETDATE() AS DATE)
WHERE
tblReps.[sActive] = 'True'
Run Code Online (Sandbox Code Playgroud)
这样,tblDaily.sDate = CAST(GETDATE() AS DATE) 在联接发生之前,联接的右侧就被过滤掉了。因此,查询将返回预期的 37 行,来自tblReps补充的匹配数据tblDaily或空值。