这个问题从之前解决的问题(非常感谢Vladimir Baranov)继续,可以在这里访问:SQL Server - CTE Recursive SUM Value From Different Table。
数据结构与以前几乎相同,只是在 EmOvertime 中有另一个名为“AttdDate”的列,表示员工的出勤日期。以下是 EmOvertime 表格中的数据示例。
Table Name : EmOvertime
EmpId AttdDate TotalOtReal
2 2016-05-09 2.00
2 2016-05-10 2.00
2 2016-05-11 2.00
2 2016-05-12 2.00
3 2016-05-12 3.00
来自 CsOrganization 和 EmHisOrganization 的数据与上一个问题相同。假设我想在2016年5月12日以TotalHours值显示所有组织数据,查询将如下所示:
WITH
CTE_OrgHours
AS
(
SELECT
Org.OrgId
,Org.OrgParentId
,Org.OrgName
,ISNULL(Overtime.TotalOtReal, 0) AS SumHours
,Overtime.AttdDate
FROM
CsOrganization AS Org
LEFT JOIN EmHisOrganization AS Emp ON Emp.OrgId = Org.OrgID
LEFT JOIN EmOvertime AS Overtime ON Overtime.EmpId = Emp.EmpId
GROUP BY
Org.OrgId
,Org.OrgParentId
,Org.OrgName
,Overtime.TotalOtReal
,Overtime.AttdDate
)
,CTE_Recursive
AS
(
SELECT
CTE_OrgHours.OrgId
,CTE_OrgHours.OrgParentId
,CTE_OrgHours.OrgName
,CTE_OrgHours.SumHours
,CTE_OrgHours.AttdDate
,1 AS Lvl
,CTE_OrgHours.OrgId AS StartOrgId
,CTE_OrgHours.OrgName AS StartOrgName
FROM CTE_OrgHours
UNION ALL
SELECT
CTE_OrgHours.OrgId
,CTE_OrgHours.OrgParentId
,CTE_OrgHours.OrgName
,CTE_OrgHours.SumHours
,CTE_OrgHours.AttdDate
,CTE_Recursive.Lvl + 1 AS Lvl
,CTE_Recursive.StartOrgId
,CTE_Recursive.StartOrgName
FROM
CTE_OrgHours
INNER JOIN CTE_Recursive ON CTE_Recursive.OrgId = CTE_OrgHours.OrgParentId
)
SELECT
StartOrgId
,StartOrgName
,SUM(SumHours) AS TotalHours
FROM CTE_Recursive
WHERE AttdDate = '2016-05-12'
GROUP BY
StartOrgId
,StartOrgName
ORDER BY StartOrgId
但是查询的结果显示如下:
OrgId OrgName TotalHours
1 X COMPANY 14.00
2 Administrator 14.00
3 Adm 1 12.00
4 Adm 2 0.00
5 Adm 1_1 0.00
虽然正确的应该是这样的:
Desired Output
OrgId OrgName TotalHours
1 X COMPANY 5.00
2 Administrator 5.00
3 Adm 1 3.00
4 Adm 2 0.00
5 Adm 1_1 0.00
似乎孩子的数据在 EmOvertime 中已经作为其父数据的数量循环,其中有4个相同的ID。因此,显示值12.00。如何解决这个问题?
非常感谢任何帮助。
答案 0 :(得分:1)
如果您对某个特定日期感兴趣,这很简单。
看起来您需要将WHERE
过滤器移动到查询的前一部分。进入CTE_OrgHours
。 CTE_OrgHours
每个组织应返回一行,其中包含相关小时数的总和。所有过滤都应在此查询中进行。递归部分后来希望在CTE_OrgHours
中每个组织有一行。
WITH
CTE_OrgHours
AS
(
SELECT
Org.OrgId
,Org.OrgParentId
,Org.OrgName
,ISNULL(SUM(Overtime.TotalOtReal), 0) AS SumHours
FROM
CsOrganization AS Org
LEFT JOIN EmHisOrganization AS Emp ON Emp.OrgId = Org.OrgID
LEFT JOIN EmOvertime AS Overtime
ON Overtime.EmpId = Emp.EmpId
AND Overtime.AttdDate = '2016-05-12'
GROUP BY
Org.OrgId
,Org.OrgParentId
,Org.OrgName
)
,CTE_Recursive
AS
(
SELECT
CTE_OrgHours.OrgId
,CTE_OrgHours.OrgParentId
,CTE_OrgHours.OrgName
,CTE_OrgHours.SumHours
,1 AS Lvl
,CTE_OrgHours.OrgId AS StartOrgId
,CTE_OrgHours.OrgName AS StartOrgName
FROM CTE_OrgHours
UNION ALL
SELECT
CTE_OrgHours.OrgId
,CTE_OrgHours.OrgParentId
,CTE_OrgHours.OrgName
,CTE_OrgHours.SumHours
,CTE_Recursive.Lvl + 1 AS Lvl
,CTE_Recursive.StartOrgId
,CTE_Recursive.StartOrgName
FROM
CTE_OrgHours
INNER JOIN CTE_Recursive ON CTE_Recursive.OrgId = CTE_OrgHours.OrgParentId
)
SELECT
StartOrgId
,StartOrgName
,SUM(SumHours) AS TotalHours
FROM CTE_Recursive
GROUP BY
StartOrgId
,StartOrgName
ORDER BY StartOrgId;