OUTER JOIN 结果缺少行,没有 WHERE 子句(找到解决方法)

Posted

技术标签:

【中文标题】OUTER JOIN 结果缺少行,没有 WHERE 子句(找到解决方法)【英文标题】:OUTER JOIN result is missing rows, no WHERE clause (Workaround found) 【发布时间】:2012-09-24 22:03:30 【问题描述】:

在底部更新。

我正在尝试做一个自外连接,对于每条记录,返回它和所有其他在它之后发生的记录,如果它本身是最新的记录,则返回 NULL。这是我的sql代码:

SELECT A.[CR#], A.REGIS_STATUSDATE, B.REGIS_STATUSDATE
FROM CR_ADMIN_REGIS_STATUS A LEFT OUTER JOIN CR_ADMIN_REGIS_STATUS B
ON A.[CR#]=B.[CR#] AND A.REGIS_STATUSDATE < B.REGIS_STATUSDATE

我的问题是,对于给定的 [CR#],当 A.REGIS_STATUSDATE 是最大值(因此 B.REGIS_STATUSDATE 不能大于它)时,该行不包含在我的结果中。

例如,如果 CR_ADMIN_REGIS_STATUS 如下所示:

CR#   REGIS_STATUSDATE
1     5/1/12
1     5/2/12
1     5/3/12
2     5/1/12
2     5/2/12

我希望我的查询结果是

CR#   A.REGIS_STATUSDATE B.REGIS_STATUSDATE
1     5/1/12             5/2/12
1     5/1/12             5/3/12
1     5/2/12             5/3/12
1     5/3/12             NULL
2     5/1/12             5/2/12
2     5/2/12             NULL

相反,我得到了这个:

CR#   A.REGIS_STATUSDATE B.REGIS_STATUSDATE
1     5/1/12             5/2/12
1     5/1/12             5/3/12
1     5/2/12             5/3/12
2     5/1/12             5/2/12

鉴于我的查询是 LEFT OUTER JOIN,并且我没有 WHERE 子句,我希望原始表中的所有行都在结果中,但事实并非如此。我在这里错过了什么?

编辑:这是在 Access 2007 中

更新:我决定看看如果我将表 CR_ADMIN_REGIS_STATUS 的部分复制到一个单独的表中并针对它运行我的查询会发生什么。即使我刚刚直接将整个表复制到新表中(手动),查询仍然有效!这只是实际复制和粘贴时的情况,但当我 SELECT * INTO 另一个表时,问题会持续存在。 最终我发现,如果我对

运行查询
SELECT *
FROM CR_ADMIN_REGIS_STATUS
UNION ALL SELECT TOP 1 * 
FROM CR_ADMIN_REGIS_STATUS;

我的查询返回了所需的结果,而不是 CR_ADMIN_REGIS_STATUS 本身。奇怪的。我也对一个从一开始就有效的类似表进行了类似的查询,所以这似乎是一个仅限于这个表的问题。

【问题讨论】:

这也让我摸不着头脑 在 MS Access 2010 中运行您的查询,我得到了您的预期结果。 【参考方案1】:

你没有错过任何东西。 如果发生这种情况,那就是错误。

MS-Access 使用的引擎有几个错误。我在具有“复杂”ON 条件的连接中看到了类似的无效行为。查看 Access 给出错误结果的另一个 SO 问题:Why does my left join in Access have fewer rows than the left table?

您可以在 SQL-Server、Oracle、Postgres 甚至 mysql 中尝试使用相同数据的查询,您将获得正确的预期结果。


作为一种解决方法,您可以尝试使用UNION 重写查询,但永远无法确定其正确性:

SELECT A.[CR#], A.REGIS_STATUSDATE, B.REGIS_STATUSDATE
FROM CR_ADMIN_REGIS_STATUS A 
  INNER JOIN CR_ADMIN_REGIS_STATUS B
    ON  A.[CR#]=B.[CR#] 
    AND A.REGIS_STATUSDATE < B.REGIS_STATUSDATE

UNION ALL

SELECT A.[CR#], A.REGIS_STATUSDATE, NULL
FROM CR_ADMIN_REGIS_STATUS A 
WHERE NOT EXISTS
      ( SELECT *
        FROM CR_ADMIN_REGIS_STATUS B
        WHERE A.[CR#]=B.[CR#] 
          AND A.REGIS_STATUSDATE < B.REGIS_STATUSDATE
      ) ;

【讨论】:

我在 MS Access 中得到了预期的结果。 感谢您的快速回答,尽管听到这个错误令人失望。我会尝试你的解决方法。 @Remou:当我回答另一个问题时,我做了一些测试,有 2 个表和很少的行,每行 2 或 3 个。具有ON a.id=b.id OR a.x IS NULL 或类似条件的查询会产生非常奇怪的结果。 @Remou:我也在 2007 版本中测试过。但这种情况似乎比另一种情况更正常和普遍。我对这个错误感到相当惊讶,但这更令人惊讶,因为没有涉及 Null。

以上是关于OUTER JOIN 结果缺少行,没有 WHERE 子句(找到解决方法)的主要内容,如果未能解决你的问题,请参考以下文章

pgSQL FULL OUTER JOIN 'WHERE' 条件

使用 WHERE 子句中的过滤器优化 OUTER JOIN 查询。(查询规划器)

Oracle left outer join with is null in JOIN vs WHERE 条件(示例)

Linq-to-Entities:带有 WHERE 子句和投影的 LEFT OUTER JOIN

SQL 查询条件放在LEFT OUTER JOIN 的ON语句后与放在WHERE中的区别

Inner Join, Left Outer Join和Association的区别