【问题标题】:Using CTE with hierarchical data and 'cumulative' values将 CTE 与分层数据和“累积”值一起使用
【发布时间】:2016-03-15 00:51:13
【问题描述】:

我正在使用城市、国家和大洲的示例层次结构试验 SQL 公用表表达式,以及访问过和未访问过的示例。

表格t_hierarchy 如下所示:

(注意:visited 列对于非城市故意为 NULL,因为我希望这是一个动态计算的百分比。)

然后我使用下面的 SQL 根据t_hierarchy 中的数据创建了一个递归结果集:

WITH myCTE (ID, name, type, parentID, visited, Depth)
 AS
 (
    Select ID, name, type, parentID, visited, 0 as Depth From t_hierarchy where parentID IS NULL
    UNION ALL
    Select t_hierarchy.ID, t_hierarchy.name, t_hierarchy.type, t_hierarchy.parentID, t_hierarchy.visited, Depth + 1 
    From t_hierarchy 
    inner join myCte on t_hierarchy.parentID = myCte.ID
 )

Select ID, name, type, parentID, Depth, cnt.numDirectChildren, visited
FROM myCTE
LEFT JOIN (
          SELECT  theID = parentID, numDirectChildren = COUNT(*)
          FROM    myCTE
          GROUP BY parentID
        ) cnt ON cnt.theID = myCTE.ID

 order by ID

结果如下:

我现在想做的,我正在努力的,是创建一个列,例如visitedPercentage 显示层次结构中每个“级别”的访问过的城市百分比(根据国家和大洲对城市进行不同的处理)。解释一下,沿着“树”往上走:

  • 马德里将是 100%,因为它已被访问过 (visited = 1)
  • 巴塞罗那将是 0%,因为它没有被访问过 (visited = 0)
  • 因此西班牙将是 50%,因为它有 2 个直系子女,一个是 100%,另一个是 0%
  • 因此欧洲为 50%,因为西班牙为 50%,法国为 100%(访问过巴黎),德国为 0%(未访问过柏林)

我希望这是有道理的。我有点想说“如果它不是城市,请根据所有直系子女的visitedPercentage 计算出这个级别的visitedPercentage,否则只显示 100% 或 0%。任何非常感谢您的指导。


更新: 我已经设法使用Daniel Gimenez 的建议进一步推进到法国 100、西班牙 50 等。但顶级项目(例如欧洲)仍然是 0,如下所示:

我认为这是因为计算是在查询的递归部分之后完成的,而不是在其中。 IE。这一行:

SELECT... , visitPercent = SUM(CAST visited AS int) / COUNT(*) FROM myCTE GROUP BY parentID

说“查看visited 列的子对象,计算值的总和,并将结果显示为visitPercent”,而应该说“查看现有的visitPercent 值先前的计算”,如果这有意义的话。我不知道从这里去哪里! :)

【问题讨论】:

  • 嘿@valoulkh 我没有时间处理这个问题,但是您需要第二个递归 CTE,它使用 myCTE 来得出每个层次结构中的所有相关城市。 SELECT ID, parentID FROM... UNION ALL SELECT ID, [parent's parentID] FROM newCTE INNER JOIN myCTE
  • 没问题,感谢您迄今为止的帮助。我会尝试按照你的逻辑:)

标签: sql sql-server-2008 common-table-expression hierarchical-data


【解决方案1】:

我想我已经做到了,使用 2 个 CTE。最后,更容易获得每个级别(子代、孙代等)的后代总数,并使用它来计算总体百分比。

那是痛苦的。有一次输入“CATS”而不是“CAST”让我困惑了大约 10 分钟。

with cte1 (ID,parentID,type,name,visited,Lvl) as (
    select t.ID, t.parentID, t.type, t.name, t.visited, 0 as [Lvl]
    from t_hierarchy t
    where t.parentID is not null
    union all
    select c.ID, t.parentID, c.type, c.name, c.visited, c.Lvl + 1
    from t_hierarchy t
        inner join cte1 c on c.parentID = t.ID
    where t.parentID is not null
),
cte2 (ID,name,type,parentID,parentName_for_reference,visited,Lvl) as (
    Select t_hierarchy.ID, t_hierarchy.name, t_hierarchy.type, t_hierarchy.parentID, p.name as parentName_for_reference, t_hierarchy.visited, 0 as Lvl
        From t_hierarchy
        left join t_hierarchy p ON p.ID = t_hierarchy.parentID
        where t_hierarchy.parentID IS NULL
    UNION ALL
    Select t_hierarchy.ID, t_hierarchy.name, t_hierarchy.type, t_hierarchy.parentID,p.name as parentName_for_reference, t_hierarchy.visited, Lvl + 1 
    From t_hierarchy
    inner join cte2 on t_hierarchy.parentID = cte2.ID
    inner join t_hierarchy p ON p.ID = t_hierarchy.parentID
)

select cte2.ID,cte2.name,cte2.type,cte2.parentID,cte2.parentName_for_reference,cte2.visited,cte2.Lvl
,CASE WHEN type = 'city' THEN 'N/A' ELSE CAST(cnt.totalDescendents as varchar) END AS totalDescendents
,CASE WHEN type = 'city' THEN 'N/A' ELSE CAST(COALESCE(cnt2.totalDescendentsVisited,0) as varchar) END AS totalDescendentsVisited
,CASE WHEN type = 'city' THEN 'N/A' ELSE CAST((CAST(ROUND(CAST(COALESCE(cnt2.totalDescendentsVisited,0) as float)/CAST(cnt.totalDescendents as float),2) AS numeric(36,2))*100) as varchar) END as asPercentage
from cte2
left JOIN (
     SELECT  theID = parentID, COUNT(*) as totalDescendents
     FROM cte1
     WHERE type = 'city'
     GROUP BY parentID
  ) cnt ON cnt.theID = cte2.ID
 left JOIN (
     SELECT  theID = parentID, COUNT(*) as totalDescendentsVisited
     FROM cte1
     WHERE type = 'city' AND visited = 1
     GROUP BY parentID
  ) cnt2 ON cnt2.theID = cte2.ID
ORDER BY ID

这些帖子很有帮助:

【讨论】:

    猜你喜欢
    • 2020-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多