完全外部连接不起作用 - 无论空活动如何,都需要返回所有日期

Posted

技术标签:

【中文标题】完全外部连接不起作用 - 无论空活动如何,都需要返回所有日期【英文标题】:Full Outer Join Not Working - Need to return all dates regardless of null activity 【发布时间】:2021-09-27 02:26:11 【问题描述】:

无论是否有活动(tTimesheets 表),我都需要为当月的每个日期(DATES 表)返回一行

在设计器中构建此查询,我远非精通,但我正在努力使这项工作:)

根据我的谷歌搜索,我相信 WHERE 子句与我的 FULL OUTER JOIN 混淆了。看起来派生表可能是解决方案?或者可能需要将一些条件带入连接而不是 WHERE 子句。

我已经在派生表上阅读了这个BLOG,但就是想不通

再次感谢您的帮助!

SELECT tProjects.ProjectName,
       tProjects.ProjectID,
       Dates.Date,
       Dates.MonthNameYear,
       tUsers.id,
       tUsers.Name,
       sum(tTimesheets.ActivityTime) as Time,
       tExpenses.ExpenseID,
       tClients.ClientName
FROM tClients
    INNER JOIN tProjects
        INNER JOIN tTimesheets
            ON tProjects.ProjectID = tTimesheets.ProjectID
        INNER JOIN tUsers
            ON tTimesheets.CreatedBy = tUsers.id
        ON tClients.ClientID = tProjects.ClientID
    LEFT OUTER JOIN tExpenses
        INNER JOIN tExpenseType
            ON tExpenses.CategoryId = tExpenseType.Id
        ON tTimesheets.CreatedBy = tExpenses.CreatedBy
           AND CAST(tTimesheets.ActivityDate AS date) = CAST(tExpenses.ExpenseDate AS DateTime)
           AND tTimesheets.ProjectID = tExpenses.ProjectID
    FULL OUTER JOIN Dates
        ON CAST(tTimesheets.ActivityDate AS date) = CAST(Dates.Date AS date)
   
WHERE        
(tProjects.ProjectName in (@parmProjects) OR tProjects.ProjectName is null)
AND
(Dates.MonthNameYear in (@parmDate) OR Dates.MonthNameYear is null)
AND
(tUsers.Name in (@parmUser) OR tUsers.Name is null)

GROUP BY 
         tUsers.Name,
         tUsers.id,
         Dates.Date,
         Dates.MonthNameYear,
         tProjects.ProjectName,
         tProjects.ProjectID,
         tExpenses.ExpenseID,
         tClients.ClientName

 ORDER BY Dates.Date

【问题讨论】:

Dates 移到顶部FROM Dates 然后LEFT JOIN 其他所有内容,并将所有WHERE 条件放在ON 子句中 仅供参考,in (@parmProjects) 不太可能按照您的想法行事。 或将日期留在原处并使其成为正确的加入。本质上包括所有客户,但前提是他们有项目和时间表。及其相关费用;但前提是他们有费用类型。对于上述所有内容,包括日期中的所有日期以及存在的相关时间表。大多数人不喜欢混合左/右连接,因为它更容易阅读。从维护的角度来看,通常首选从最大行到最小行的左连接流。 【参考方案1】:

这里不需要FULL JOIN。你只需要从DatesLEFT JOIN 开始。

所有与其他表相关的WHERE 条件都需要放在ON 子句中。

补充说明:

CAST(... AS date) 在用作连接或过滤条件时效率低下。最好使用日期间隔范围。如果你有一个Date 表,它应该被声明为date 数据类型。我没有更改它,因为我不知道您的数据。 d.MonthNameYear in (@parmDate) OR d.MonthNameYear is null 有点怀疑:为什么 MonthNameYear 在日期表上为空。 in (@parmDate) 很奇怪:它应该匹配一个列表吗?如果是这样,那是行不通的。 此外,像这样使用 OR 可能会导致性能问题 使用简短而有意义的表别名,使查询更具可读性
SELECT p.ProjectName,
       p.ProjectID,
       d.Date,
       d.MonthNameYear,
       u.id,
       u.Name,
       sum(ts.ActivityTime) as Time,
       e.ExpenseID,
       c.ClientName
FROM Dates d
LEFT JOIN
   (tClients c
    INNER JOIN tProjects p
        ON c.ClientID = p.ClientID
        AND (p.ProjectName in (@parmProjects) OR p.ProjectName is null)
    INNER JOIN tTimesheets ts
        ON p.ProjectID = ts.ProjectID
    INNER JOIN tUsers u
        ON ts.CreatedBy = u.id
        AND
        (u.Name in (@parmUser) OR u.Name is null)

    LEFT OUTER JOIN
       (tExpenses e
        INNER JOIN tExpenseType
            ON e.CategoryId = et.Id
       ) ON ts.CreatedBy = e.CreatedBy
           AND CAST(ts.ActivityDate AS date) = CAST(e.ExpenseDate AS DateTime)
           AND ts.ProjectID = e.ProjectID
)
  ON CAST(ts.ActivityDate AS date) = CAST(d.Date AS date)
   
WHERE        
(d.MonthNameYear in (@parmDate) OR d.MonthNameYear is null)

GROUP BY 
         u.Name,
         u.id,
         d.Date,
         d.MonthNameYear,
         p.ProjectName,
         p.ProjectID,
         e.ExpenseID,
         c.ClientName

ORDER BY d.Date;

另一种方法是将所有其他连接放在派生表或 CTE 中。这有时会更容易编写。

【讨论】:

非常感谢!!希望我能给你买杯啤酒。我已经采纳了您的建议并将它们全部纳入最终查询,OR 是我正在做的一件愚蠢的事情,现在不需要并删除,谢谢!

以上是关于完全外部连接不起作用 - 无论空活动如何,都需要返回所有日期的主要内容,如果未能解决你的问题,请参考以下文章

“空”功能的外部过程中的弯路钩子不起作用

从 Android 上的 Qt 应用程序通过(显式)意图调用外部活动 - putExtra 不起作用

通过外部触摸事件关闭对话框不起作用

乐观锁定问题-rejectValue 不起作用,无论如何都保存了坏域

具有多个条件的 SQL 查询不起作用

从 Kettle 外部的属性文件连接数据库连接不起作用