SQL Server - CTE递归,在子数据中循环?

时间:2016-05-10 01:53:39

标签: sql sql-server

这个问题从之前解决的问题(非常感谢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。如何解决这个问题?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

如果您对某个特定日期感兴趣,这很简单。

看起来您需要将WHERE过滤器移动到查询的前一部分。进入CTE_OrgHoursCTE_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;