Sql Oracle分层总和(从叶到根的距离)
我想获得有关Oracle 11gR2分层查询的帮助。我很难回答这些问题 事实上,这是一个二合一的问题,需要两种不同的方法 我正在寻找一种方法来获得所有个人记录到根的距离,而不是相反的距离。我的数据是树状结构:Sql Oracle分层总和(从叶到根的距离),sql,oracle,plsql,tree,Sql,Oracle,Plsql,Tree,我想获得有关Oracle 11gR2分层查询的帮助。我很难回答这些问题 事实上,这是一个二合一的问题,需要两种不同的方法 我正在寻找一种方法来获得所有个人记录到根的距离,而不是相反的距离。我的数据是树状结构: CREATE TABLE MY_TREE (ID_NAME VARCHAR2(1) PRIMARY KEY, PARENT_ID VARCHAR2(1), PARENT_DISTANCE NUMBER(2) ); INSERT INTO MY_TREE (ID_NAME,PARENT
CREATE TABLE MY_TREE
(ID_NAME VARCHAR2(1) PRIMARY KEY,
PARENT_ID VARCHAR2(1),
PARENT_DISTANCE NUMBER(2)
);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('A',NULL,NULL);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('B','A',1);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('C','B',3);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('D','B',5);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('E','C',7);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('F','D',11);
INSERT INTO MY_TREE (ID_NAME,PARENT_ID,PARENT_DISTANCE) VALUES('G','D',13);
从层次上看,我的数据如下所示,但我有多个独立根和更多级别:
在第一种方法中,我正在寻找一个能给出以下结果的查询:
LEVEL ROOT NODE ID_NAME ROOT_DISTANCE
----- ---- ---- ------- -------------
1 A null A null
2 A null B 1
3 A B C 4
4 A B E 11
3 A B D 6
4 A D F 17
4 A D G 19
因此,
节点列表示最近拆分元素的ID_名称
根距离列表示从元素到根的距离ex:ID\u NAME=G的根距离是从G到A:G13+D5+B1=19的距离
在这种方法中,我将始终指定最多2个根
第二种方法必须是PL/SQL脚本,该脚本将执行相同的计算根距离,但以迭代方式,并将结果写入新表中。我想运行此脚本一次,以便处理所有根~1000
以下是我对脚本的看法:
对于所有根,我们需要找到相关联的叶,然后计算叶和根之间的所有元素从叶到根的距离,并将其放入表中。
性能透视图需要此脚本,因此,如果已计算某个元素,例如:由另一个叶计算的拆分节点,则需要停止计算并传递到下一个叶,因为我们已经知道从那里到根的结果。例如,如果系统先计算E-C-B-A,然后计算F-D-B-A,则不应再次计算B-A截面,因为它是在第一次通过时完成的
你可以回答其中一个或两个问题,但我需要回答这两个问题
谢谢大家! 这里有一个选项显示了如何获取问题的第一部分:
SQL> with temp as
2 (select level lvl,
3 ltrim(sys_connect_by_path(id_name, ','), ',') path
4 from my_tree
5 start with parent_id is null
6 connect by prior id_name = parent_id
7 ),
8 inter as
9 (select t.lvl,
10 t.path,
11 regexp_substr(t.path, '[^,]+', 1, column_value) col
12 from temp t,
13 table(cast(multiset(select level from dual
14 connect by level <= regexp_count(path, ',') + 1
15 ) as sys.odcinumberlist ))
16 )
17 select i.lvl,
18 i.path,
19 sum(m.parent_distance) dis
20 from inter i join my_tree m on m.id_name = i.col
21 group by i.lvl, i.path
22 order by i.path;
LVL PATH DIS
---- ---------- ----------
1 A
2 A,B 1
3 A,B,C 4
4 A,B,C,E 11
3 A,B,D 6
4 A,B,D,F 17
4 A,B,D,G 19
7 rows selected.
SQL>
试试这个:
WITH brumba(le_vel,root,node,id_name,root_distance) AS (
SELECT 1 as le_vel, id_name as root, null as node, id_name, to_number(null) as root_distance
FROM MY_TREE WHERE parent_id IS NULL
UNION ALL
SELECT b.le_vel + 1, b.root,
CASE WHEN 1 < (
SELECT count(*) FROM MY_TREE t1 WHERE t1.parent_id = t.parent_id
)
THEN t.parent_id ELSE b.node
END,
t.id_name, coalesce(b.root_distance,0)+t.parent_distance
FROM MY_TREE t
JOIN brumba b ON b.id_name = t.parent_id
)
SELECT * FROM brumba
演示:
不需要使用PL/SQL进行第二种方法-上面的SQL将立即计算所有在parent_id列中为null的根节点的结果。
只需添加一个前缀,插入tablenamecol1,col2。。。科恩。。。或将表名创建为。。。对上面的查询。
上面的演示包含后一个选项的示例CREATE TABLE xxx AS query,下面是如何使用分层连接查询解决此问题 在大多数分层问题中,分层查询将比递归查询快。然而,您的问题并不是纯粹的分层问题——您需要计算到根的距离,并且与递归不同的是,您无法通过分层查询在一次过程中获得该距离。所以听到你的消息会很有趣两种方法之间是否存在显著的性能差异。值得一提的是,在您提供的非常小的数据样本上,优化器估计使用connect by的成本为5,而递归解决方案的成本为48;在现实生活中这是否意味着什么,你会发现,希望你也能让我们知道 在分层查询中,我标记出有两个或更多子级的父级,并为此使用分析函数,以避免联接。然后我构建层次结构,在最后一步,我聚合以获得所需的位。与递归解决方案一样,这将在一个SQL查询中为您提供所需的一切—所有根和所有节点;不需要PL/SQL代码
with
branching (id_name, parent_id, parent_distance, b) as (
select id_name, parent_id, parent_distance,
case when count(*) over (partition by parent_id) > 1 then 'y' end
from my_tree
)
, hierarchy (lvl, leaf, id_name, parent_id, parent_distance, b) as (
select level, connect_by_root id_name, id_name, parent_id, parent_distance, b
from branching
connect by id_name = prior parent_id
)
select max(lvl) as lvl,
min(id_name) keep (dense_rank last order by lvl) as root,
leaf as id_name,
min(decode(b, 'y', parent_id))
keep (dense_rank first order by decode(b, 'y', lvl)) as node,
sum(parent_distance) as root_distance
from hierarchy
group by leaf;
LVL ROOT ID_NAME NODE ROOT_DISTANCE
--- ------- ------- ------- -------------
1 A A
2 A B 1
3 A C B 4
3 A D B 6
4 A E B 11
4 A F D 17
4 A G D 19
哇!这与我试图从分组函数求和的目的相去甚远。您甚至不使用连接条件!再一次,哇!我甚至不知道我们可以引用WITH条款本身。这叫什么?子查询分解?我期待着在我的真实环境中测试您的解决方案!是的,这是符合ANSII SQL的递归查询。CONNECT BY是Oracle特有的递归语法,但使用CONNECT BY无法解决此问题。我将比较此方法与上述方法的性能。非常感谢您的回答!