计算分层 SQL 数据中的子项数

Posted

技术标签:

【中文标题】计算分层 SQL 数据中的子项数【英文标题】:Counting number of children in hierarchical SQL data 【发布时间】:2011-01-21 09:25:57 【问题描述】:

对于一个简单的数据结构,例如:

ID    parentID    Text        Price
1                 Root
2     1           Flowers
3     1           Electro
4     2           Rose        10
5     2           Violet      5
6     4           Red Rose    12
7     3           Television  100
8     3           Radio       70
9     8           Webradio    90

作为参考,层次树如下所示:

ID    Text        Price
1     Root
|2    Flowers
|-4   Rose        10
| |-6 Red Rose    12
|-5   Violet      5
|3    Electro
|-7   Television  100
|-8   Radio       70
  |-9 Webradio    90

我想计算每个级别的孩子人数。所以我会得到一个新列“NoOfChildren”,如下所示:

ID    parentID    Text        Price  NoOfChildren
1                 Root               8
2     1           Flowers            3
3     1           Electro            3
4     2           Rose        10     1
5     2           Violet      5      0
6     4           Red Rose    12     0
7     3           Television  100    0
8     3           Radio       70     1
9     8           Webradio    90     0

我阅读了一些有关分层数据的内容,但不知何故我陷入了 parentID 上的多个内部联接。也许有人可以在这里帮助我。

【问题讨论】:

您的层次结构树与您的输入不匹配。 而且您的输出似乎与您的层次结构不匹配 。从您的层次结构来看,我会假设 ID 的 4 和 7 有 0 个孩子。 你是完全正确的,搞砸了层次结构树+输出,将修复 【参考方案1】:

使用CTE 会得到你想要的。

递归遍历所有子节点,记住根。 COUNT 每个根的项目。 JOIN 这些再次与您的原始表格一起生成结果。

测试数据

DECLARE @Data TABLE (
  ID INTEGER PRIMARY KEY
  , ParentID INTEGER
  , Text VARCHAR(32)
  , Price INTEGER
)

INSERT INTO @Data
  SELECT 1, Null, 'Root', NULL
  UNION ALL SELECT 2, 1, 'Flowers', NULL
  UNION ALL SELECT 3, 1, 'Electro', NULL
  UNION ALL SELECT 4, 2, 'Rose', 10
  UNION ALL SELECT 5, 2, 'Violet', 5
  UNION ALL SELECT 6, 4, 'Red Rose', 12
  UNION ALL SELECT 7, 3, 'Television', 100
  UNION ALL SELECT 8, 3, 'Radio', 70
  UNION ALL SELECT 9, 8, 'Webradio', 90

SQL 语句

;WITH ChildrenCTE AS (
  SELECT  RootID = ID, ID
  FROM    @Data
  UNION ALL
  SELECT  cte.RootID, d.ID
  FROM    ChildrenCTE cte
          INNER JOIN @Data d ON d.ParentID = cte.ID
)
SELECT  d.ID, d.ParentID, d.Text, d.Price, cnt.Children
FROM    @Data d
        INNER JOIN (
          SELECT  ID = RootID, Children = COUNT(*) - 1
          FROM    ChildrenCTE
          GROUP BY RootID
        ) cnt ON cnt.ID = d.ID

【讨论】:

感谢您的明确回答,完美的解决方案。想告诉我“;”的用法吗?在使用 WITH 语句时,有时会出现语法错误,因为我没有那个讨厌的“;”。我是否总是必须“转义”带有附加 ; 的 WITH 语句? @moontear: 定义CTEWITH 子句可能与定义表提示的WITH 子句混合使用。如果它不是批处理中的第一个语句,则前者应该用分号显式分隔。 +1,几乎和使用 split 函数的 CROSS APPLY 一样难,但并不常见 ;-) @moontear,只要养成总是在 WITH 命令旁边的分号编码的习惯,例如:;WITH,你永远不会有问题(就像在 @Lieven 的代码中一样) @MehdiDaustany - 您可以添加以下查询提示以超越默认递归级别 SELECT ... FROM ... OPTION (MAXRECURSION 200)【参考方案2】:

考虑使用经过修改的前序树遍历方式来存储分层数据。见http://www.sitepoint.com/hierarchical-data-database/

确定任何节点的子节点数变得很简单:

SELECT (right-left-1) / 2 AS num_children FROM ...

【讨论】:

你为我节省了很多时间。对我来说最好的答案:) 这个系统太棒了!不幸的是,由于我必须使用已建立的系统,因此我无法使用它,但我会牢记它以确保新的开发。

以上是关于计算分层 SQL 数据中的子项数的主要内容,如果未能解决你的问题,请参考以下文章

删除 SQL 表中的分层数据

实时数仓方案如何选型和构建

实时数仓方案如何选型和构建

数据仓库数仓分层设计架构

Flink实时数仓实时的需求

您如何在 SQL Server 中计算每天计划中的任务数?