我有类似的查询:
SELECT *
FROM TableA a
LEFT JOIN TABLEB b
ON a.ColA = b.ColA
WHERE b.Col1 IS NULL
OR (b.Col1 = A AND b.Col2 = B AND b.Col3 BETWEEN @StartDate AND @EndDate)
我得到一个奇怪的结果集,因为我期望从TableA返回每一行,但查询的日期部分搞砸了结果集只返回3行。我知道这一点,因为当我删除日期时间过滤器并留下其他两个过滤器时,我得到了正确的结果。
真的难倒这似乎是'意外行为'我无法从逻辑上解释为什么会发生这种情况。
答案 0 :(得分:3)
尽管您的语法错误....
您应该执行正确的连接,因为where子句中的所有逻辑都在表B上。
SELECT *
FROM TABLEB b
RIGHT JOIN TABLEA a on a.SomeId = b.SomeId
WHERE b.Col1 IS NULL OR (b.Col1 = A AND b.Col2 = B AND b.Col3 BETWEEN @StartDate AND @EndDate)
然而,这可能是你真正想要的......
SELECT *
FROM TableA a
LEFT JOIN TABLEB b on b.SomeId = a.SomeId and b.Col1 = A AND b.Col2 = B AND b.Col3 BETWEEN @StartDate AND @EndDate
WHERE b.Col1 IS NULL
答案 1 :(得分:2)
这接近再现你看到的问题吗?
DECLARE @StartDate datetime;
DECLARE @EndDate datetime;
-- Date range is the year 2000
SET @StartDate = '2000-01-01';
SET @EndDate = '2000-12-31';
DECLARE @TableA TABLE
(
col1 int NULL,
col2 int NULL
);
DECLARE @TableB TABLE
(
col1 int NULL,
col2 int NULL,
col3 datetime NULL
);
和
INSERT @TableA
(col1, col2)
VALUES
(1, 1);
-- Row joins but date is not in year 2000
INSERT @TableB
(col1, col2, col3)
VALUES
( 1, 1, '2001-07-01');
-- Test query (no rows)
SELECT
a.*,
b.*
FROM @TableA AS a
LEFT JOIN @TableB AS b
ON b.col1 = a.col1
WHERE
b.col1 IS NULL
OR
(
b.col1 = a.col1
AND b.col2 = a.col2
AND b.col3 BETWEEN @StartDate AND @EndDate
);
外连接的逻辑很容易ON
子句和NULL
- WHERE
子句中的扩展行很快就会失控。我可能会使用NOT EXISTS
和/或简单UNION ALL
重写查询,以便在尝试使用OUTER JOIN
重写它之前获得正确的结果(可能是为了获得性能优势?)。
答案 2 :(得分:0)
你的SQL会以这种方式更好地写:
SELECT *
FROM TableA a
LEFT JOIN TABLEB b ON a.col1 = b.col2
WHERE (b.col3 IS NULL) or (b.Col3 BETWEEN @StartDate AND @EndDate)
b.Col1 = A AND b.Col2 = B
应该在LEFT JOIN片段,因为这是左连接语句的正确语法。
所以上面的SQL现在可以被翻译成:select tableA中的每一行和tableB中的那些行,其中tableA中的col1等于来自tableB的col2,通过col3从tableB过滤结果,其中它是null或者来自tableB的col3,它是值在@StartDate和@EndDate之间。
希望它有所帮助。
最好的问候。
答案 3 :(得分:0)
我修复了这个问题,我只是将它们更改为派生表,以便在连接之前应用所有谓词。
感谢大家的帮助。