问题描述
各位专家好。我想计算分层查询中leaves属性计数的总和
我想获取每个id的输出,其中包含其属性的计数以及在整个层次结构中行走的其叶子属性的总计数。例如: 33有3个属性 (M,N和O),但没有叶子; 27的属性计数为2,叶子属性计数为6 (属性计数为31、32和33)。
这可以通过标量子查询来实现,但效果很差。这可以w/ sql吗?
Rgds
科恩
create table hq_test (parent_id NUMBER, child_id NUMBER); INSERT INTO hq_test (parent_id, child_id) VALUES (25,26); INSERT INTO hq_test (parent_id, child_id) VALUES (25,27); INSERT INTO hq_test (parent_id, child_id) VALUES (26,28); INSERT INTO hq_test (parent_id, child_id) VALUES (26,29); INSERT INTO hq_test (parent_id, child_id) VALUES (26,30); INSERT INTO hq_test (parent_id, child_id) VALUES (27,31); INSERT INTO hq_test (parent_id, child_id) VALUES (27,32); INSERT INTO hq_test (parent_id, child_id) VALUES (27,33); INSERT INTO hq_test (parent_id, child_id) VALUES (30,34); INSERT INTO hq_test (parent_id, child_id) VALUES (NULL,25); create table hq_test_attr (id NUMBER, val VARCHAR2(100)); INSERT INTO hq_test_attr (id, val) VALUES (26, 'A'); INSERT INTO hq_test_attr (id, val) VALUES (26, 'B'); INSERT INTO hq_test_attr (id, val) VALUES (27, 'C'); INSERT INTO hq_test_attr (id, val) VALUES (27, 'D'); INSERT INTO hq_test_attr (id, val) VALUES (28, 'E'); INSERT INTO hq_test_attr (id, val) VALUES (28, 'F'); INSERT INTO hq_test_attr (id, val) VALUES (28, 'G'); INSERT INTO hq_test_attr (id, val) VALUES (29, 'H'); INSERT INTO hq_test_attr (id, val) VALUES (30, 'I'); INSERT INTO hq_test_attr (id, val) VALUES (31, 'J'); INSERT INTO hq_test_attr (id, val) VALUES (31, 'K'); INSERT INTO hq_test_attr (id, val) VALUES (32, 'L'); INSERT INTO hq_test_attr (id, val) VALUES (33, 'M'); INSERT INTO hq_test_attr (id, val) VALUES (33, 'N'); INSERT INTO hq_test_attr (id, val) VALUES (33, 'O');复制
我想获取每个id的输出,其中包含其属性的计数以及在整个层次结构中行走的其叶子属性的总计数。例如: 33有3个属性 (M,N和O),但没有叶子; 27的属性计数为2,叶子属性计数为6 (属性计数为31、32和33)。
这可以通过标量子查询来实现,但效果很差。这可以w/ sql吗?
Rgds
科恩
专家解答
所以你想要每个节点下面的子树中所有属性的总和,包括它自己?
在处理树木时,我发现有一个图表显示你想要的东西是有帮助的。所以我们开始:

方框中的数字是节点ID,后跟其属性的编号 (在括号中)。
每个框上方的数字是其下方子树中所有属性的总和。
但是我们如何计算呢?
首先,使用深度优先搜索为每个节点分配一个序列号。在我们的图中每个框的左侧显示这些显示:

要获得节点下方的总数,您需要将其本身的值累加到树中相同级别或更低级别的下一个节点,但不包括该节点。
例如,节点26在搜索中是第二。您需要添加它和27之间的所有属性,这是7。所以它的总数是节点2和6之间的一切。
这就是概念。让我们把它翻译成SQL。
首先你需要计算每个节点有多少属性。这是一个标准的外部联接 (某些节点没有属性) 和分组:
接下来你需要建造这棵树。我已经做到了这一点使用递归与这使您能够指定深度优先搜索 (默认值),并按照访问它们的顺序为每个节点分配序列号:
这就是有趣的地方。您希望 “期待” 到下一个节点,其中级别 <= 当前级别。您可以使用子查询来找到它,例如:
但是此查询将针对树中的每个节点运行。这可能不会很好地扩展。
幸运的是你在12摄氏度。所以模式匹配可以来拯救!:)
要使用它,请将子树变量定义为级别大于匹配中第一行的行:
您需要为表格中的每一行执行此操作。但是默认情况下,match_recognize完成匹配后,转到数据集中的下一行。这意味着它将从根开始,遍历树一次,然后停止!
要解决此问题,您需要 “返回” 第二行。第三次,第四次,等等。为此,请添加:
这使它能够查找每行的所有子树。
要完成所有工作,您需要做的是在 “度量” 子句中定义输出中所需的列。要获得总属性,请将所有计数求和。对于您希望看到的任何其他内容,例如父级,子级等,返回每一列的第一 ()。
把它们放在一起,你会得到:
在处理树木时,我发现有一个图表显示你想要的东西是有帮助的。所以我们开始:
方框中的数字是节点ID,后跟其属性的编号 (在括号中)。
每个框上方的数字是其下方子树中所有属性的总和。
但是我们如何计算呢?
首先,使用深度优先搜索为每个节点分配一个序列号。在我们的图中每个框的左侧显示这些显示:
要获得节点下方的总数,您需要将其本身的值累加到树中相同级别或更低级别的下一个节点,但不包括该节点。
例如,节点26在搜索中是第二。您需要添加它和27之间的所有属性,这是7。所以它的总数是节点2和6之间的一切。
这就是概念。让我们把它翻译成SQL。
首先你需要计算每个节点有多少属性。这是一个标准的外部联接 (某些节点没有属性) 和分组:
select h.parent_id, h.child_id, count(a.id) c from hq_test h left join hq_test_attr a on h.child_id = a.id group by h.parent_id, h.child_id;复制
接下来你需要建造这棵树。我已经做到了这一点使用递归与这使您能够指定深度优先搜索 (默认值),并按照访问它们的顺序为每个节点分配序列号:
tree (par, chd, c, tot, pth, lev) as ( select parent_id, child_id, c, c, child_id || '', 1 lev from counts c where parent_id is null union all select c.parent_id, c.child_id, c.c, 0 , pth || '|' || c.child_id, lev + 1 lev from tree t join counts c on t.chd = c.parent_id ) search depth first by chd set seq复制
这就是有趣的地方。您希望 “期待” 到下一个节点,其中级别 <= 当前级别。您可以使用子查询来找到它,例如:
select min(s.seq) from tree s where s.seq > t.seq and s.lev <= t.lev复制
但是此查询将针对树中的每个节点运行。这可能不会很好地扩展。
幸运的是你在12摄氏度。所以模式匹配可以来拯救!:)
要使用它,请将子树变量定义为级别大于匹配中第一行的行:
pattern ( strt subtree* ) define subtree as lev > first (lev)复制
您需要为表格中的每一行执行此操作。但是默认情况下,match_recognize完成匹配后,转到数据集中的下一行。这意味着它将从根开始,遍历树一次,然后停止!
要解决此问题,您需要 “返回” 第二行。第三次,第四次,等等。为此,请添加:
after match skip to next row复制
这使它能够查找每行的所有子树。
要完成所有工作,您需要做的是在 “度量” 子句中定义输出中所需的列。要获得总属性,请将所有计数求和。对于您希望看到的任何其他内容,例如父级,子级等,返回每一列的第一 ()。
把它们放在一起,你会得到:
with counts as ( select h.parent_id, h.child_id, count(a.id) c from hq_test h left join hq_test_attr a on h.child_id = a.id group by h.parent_id, h.child_id ), tree (par, chd, c, tot, pth, lev) as ( select parent_id, child_id, c, c, child_id || '', 1 lev from counts c where parent_id is null union all select c.parent_id, c.child_id, c.c, 0 , pth || '|' || c.child_id, lev + 1 lev from tree t join counts c on t.chd = c.parent_id ) search depth first by chd set seq select * from tree match_recognize ( order by seq measures first(chd) as child_id, first(par) as parent_id, first(pth) as pth, first (lev) as lev, first(c) as attrs, sum(c) as subtot, first(seq) as seq after match skip to next row pattern ( strt subtree* ) define subtree as lev > first (lev) ) order by seq; CHILD_ID PARENT_ID PTH LEV ATTRS SUBTOT SEQ 25 25 1 0 15 1 26 25 25|26 2 2 7 2 28 26 25|26|28 3 3 3 3 29 26 25|26|29 3 1 1 4 30 26 25|26|30 3 1 1 5 34 30 25|26|30|34 4 0 0 6 27 25 25|27 2 2 8 7 31 27 25|27|31 3 2 2 8 32 27 25|27|32 3 1 1 9 33 27 25|27|33 3 3 3 10复制
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
Oracle DataGuard高可用性解决方案详解
孙莹
504次阅读
2025-03-26 23:27:33
Oracle RAC 一键安装翻车?手把手教你如何排错!
Lucifer三思而后行
483次阅读
2025-04-15 17:24:06
墨天轮个人数说知识点合集
JiekeXu
405次阅读
2025-04-01 15:56:03
XTTS跨版本迁移升级方案(11g to 19c RAC for Linux)
zwtian
398次阅读
2025-04-08 09:12:48
Oracle SQL 执行计划分析与优化指南
Digital Observer
374次阅读
2025-04-01 11:08:44
【纯干货】Oracle 19C RU 19.27 发布,如何快速升级和安装?
Lucifer三思而后行
360次阅读
2025-04-18 14:18:38
Oracle 19c RAC更换IP实战,运维必看!
szrsu
343次阅读
2025-04-08 23:57:08
oracle定时任务常用攻略
virvle
316次阅读
2025-03-25 16:05:19
3月“墨力原创作者计划”获奖名单公布
墨天轮编辑部
315次阅读
2025-04-15 14:48:05
风口浪尖!诚通证券扩容采购Oracle 793万...
Roger的数据库专栏
311次阅读
2025-03-24 09:42:53