完全外部联接不起作用 - 需要 return 所有日期,无论是否为空 activity

Full Outer Join Not Working - Need to return all dates regardless of null activity

无论是否有 activity (tTimesheets table),我都需要 return 每个月的每个日期 (DATES table)

在设计器中构建了这个查询,我不太精通,但我正在努力使它工作:)

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

我在派生的 table 上读过这个 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

这里不需要 FULL JOIN。您只需要从 DatesLEFT JOIN 其他一切开始。

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

补充说明:

  • CAST(... AS date) 在用作连接或过滤条件时效率低下。最好使用日期间隔范围。如果你有一个 Date table,无论如何它应该被声明为 date 数据类型。我没有更改它,因为我不知道你的数据。
  • d.MonthNameYear in (@parmDate) OR d.MonthNameYear is null 有点可疑:为什么 MonthNameYear 在日期 table 上为空。 in (@parmDate) 很奇怪:它应该匹配列表吗?如果是这样,那是行不通的。
  • 此外,像这样使用 OR 可能会导致性能问题
  • 使用简短而有意义的 table 别名,它使查询更具可读性
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;

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