【问题标题】:MS Access SQL: Troubles combining UNION ALL with a LEFT JOINMS Access SQL:将 UNION ALL 与 LEFT JOIN 结合起来的麻烦
【发布时间】:2010-12-20 22:09:17
【问题描述】:

我在 MS Access 中创建了一个查询来模拟 FULL OUTER JOIN 并组合如下所示的结果:

SELECT NZ(estimates.employee_id, actuals.employee_id) AS employee_id
, NZ(estimates.a_date, actuals.a_date) AS a_date
, estimates.estimated_hours
, actuals.actual_hours
FROM (SELECT *
      FROM estimates
      LEFT JOIN actuals ON estimates.employee_id = actuals.employee_id
         AND estimates.a_date = actuals.a_date
      UNION ALL
      SELECT *
      FROM estimates
      RIGHT JOIN actuals ON estimates.employee_id = actuals.employee_id
         AND estimates.a_date = actuals.a_date
      WHERE estimates.employee_id IS NULL
         OR estimates.a_date IS NULL) AS qFullJoinEstimatesActuals

我已将此查询保存为一个对象(我们称之为qEstimatesAndActuals)。我的目标是 LEFT JOIN qEstimatesAndActuals 与另一个表。类似于以下内容:

SELECT *
FROM qJoinedTable
LEFT JOIN (SELECT *
           FROM labor_rates) AS rates
ON qJoinedTable.employee_id = rates.employee_id
   AND qJoinedTable.a_date BETWEEN rates.begin_date AND rates.end_date

MS Access 接受语法并运行查询,但它忽略了明显在结果集中的结果。想知道日期格式是否以某种方式丢失,我在 begin_date 和 end_date 周围放置了一个 FORMAT,以强制将它们解释为短日期。奇怪的是,这产生了一个不同的结果集,但它仍然遗漏了它不应该有的结果。

我想知道查询是否以您无法左连接 UNION ALL 的结果集的方式执行。有人对此有任何想法/想法吗?有没有更好的方法来实现最终目标?

【问题讨论】:

    标签: sql ms-access


    【解决方案1】:

    我会尝试将查询的每个部分分解为自己的访问查询对象,例如

    SELECT *
      FROM estimates
      LEFT JOIN actuals ON estimates.employee_id = actuals.employee_id
         AND estimates.a_date = actuals.a_date
    

    应该是 qryOne

    SELECT *
      FROM estimates
      RIGHT JOIN actuals ON estimates.employee_id = actuals.employee_id
         AND estimates.a_date = actuals.a_date
      WHERE estimates.employee_id IS NULL
         OR estimates.a_date IS NULL
    

    应该是 qryTwo

    SELECT * FROM qryOne
    UNION ALL
    SELECT * FROM qryTwo
    

    将是 qryFullJoinEstimatesActuals,最后是

    SELECT NZ(estimates.employee_id, actuals.employee_id) AS employee_id
    , NZ(estimates.a_date, actuals.a_date) AS a_date
    , estimates.estimated_hours
    , actuals.actual_hours
    FROM qryFullJoinEstimatesActuals
    

    我发现,在复杂的 Access SQL 语句中不起作用的构造如果被分解为单独的查询对象并逐步重新组合,通常可以正常工作。此外,您可以单独测试查询的每个部分。如果证明有必要,这将帮助您找到解决方法。

    【讨论】:

    • 感谢您的提示。虽然这不是根本问题,但它 (a) 让我偶然发现了另一个不相关的错误,该错误后来可能会成为问题,并且 (b) 帮助我集中精力解决导致问题的原因。
    【解决方案2】:

    您可以找到具体的操作方法here

    您缺少一个 INNER JOIN.... UNION ALL 步骤。

    【讨论】:

    • 您引用的文章被用作 FULL JOIN 的基础(尽管我修改了语法以消除使用 INNER JOIN 的冗余 - 因为一些评论文章的人可能是完毕)。但是,创建 FULL JOIN 的语法 不是 我遇到的问题。我上面描述的问题是指当 FULL JOIN(它自己工作)的结果集与 LEFT JOIN 组合时产生的结果集。
    • 看看文章中的维恩图。正如文章所写,作者使用三个查询来获取 Set 1(INNER JOIN)、Set 2(LEFT JOIN with a WHERE 子句以删除 Set 1 结果)和 Set 3(RIGHT JOIN with a WHERE 子句以删除 Set 1结果)并使用两个 UNION ALL 将它们组合起来。这可以通过使用两个查询更简单地完成,第一个获取集合 1 和 2(LEFT JOIN 没有一个 WHERE 子句来删除 Set 1 结果),第二个获取集合 3(RIGHT JOIN with一个 WHERE 子句来删除 Set 1 结果)并使用一个 UNION ALL 来组合它们。
    • @Adam 谢谢。出于好奇,为什么不使用 SQL Server?
    【解决方案3】:

    与日期周围的奇怪行为一致,这个问题原来与使用 NZ 从 qFullJoinEstimatesActuals 中选择日期有关。 NZ 的使用似乎使数据类型不明确。因此,我帖子中示例中的以下行导致了错误:

    , NZ(estimates.a_date, actuals.a_date) AS a_date
    

    a_date 的不明确数据类型导致 BETWEEN 运算符在将 a_date 与 LEFT JOIN 中的 rates.begin_date 和 rates.end_date 进行比较时产生错误的结果。该问题已通过类型转换 NZ 函数的结果得到解决,如下所示:

    , CDate(NZ(estimates.a_date, actuals.a_date)) AS a_date
    

    【讨论】:

    • 我也对使用 Nz() 的返回类型的不可靠性感到沮丧,但根据定义,您期望其中一个参数至少在某些时候为 Null,这意味着函数需要猜测返回类型或检查有关源数据的元数据。所以,你必须自己做。也就是说,Nz() 表达式上的连接让我觉得有问题,因为它不能使用索引。
    • 这篇文章是基于显示给 UNION ALLs 的,这是有道理的。你只有一个。你怎么能得到所有的结果?
    • @David-W-Fenton 这当然是有道理的。至于设计方面的问题,您还有什么建议吗?稍微简化一下,有两个表:(1) 一个包含employee_id、week_end_date 和projected_hours 的估计表;(2) 一个包含employee_id、week_end_date 和actual_hours 的实际表。可能有员工预计要工作,但实际上没有。类似地,可能有一些员工没有计划工作,但确实工作。目标:将employee_id、week_end_date、projected_hours、actual_hours 获取到单个可查询对象中。例如,001、9/26/2010、0、10
    • 当我看到原始 SQL 并且无法直接与数据交互时,我的眼睛呆滞,所以我不能说我可以看到明显更好的解决方案。但是,每当我看到 UNION 被广泛使用时,都会给我带来麻烦,尤其是当您需要加入 UNION 时,因为您不能使用索引。 JOIN 两个表,然后 UNION 该 JOIN 的多个实例可能更有效,因为这至少会使用索引(假设是 equi-JOIN 而不是表达式)。
    猜你喜欢
    • 2016-12-29
    • 2015-09-01
    • 2018-09-21
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多