递归数据结构的常用方法是在每个对象中都有一个父指针。我的问题是通常的实施无法在一次操作中回答以下问题;相反,我需要多次查询我的数据库。有没有一个解决方案可以在单个查询中提供结果?
获取节点的所有子项列表
查找所有父节点(==根节点的最短路径)
注意:我正处于计划阶段,所以我还不限于某个数据库。
答案 0 :(得分:2)
如果“所有孩子”仅指直接孩子,只需输入一个孩子列表,以及指向每个节点上父母的指针。请注意,这将使节点移动到另一个父节点更加昂贵,因为所有(大)子节点也必须更新。
如果“所有孩子”真的意味着所有孩子,一个选项是构建每个父母的ID字符串,并将其添加为索引列。例如,如果您与孩子A
B
和孙子C
有C
,则A/B/C
列中的值为A
。现在,要查找LIKE
的所有子项,您只需在"A/%"
上进行{{1}}查询即可。但是,当您需要更改具有子节点的节点的父节点时,这仍然很昂贵。
如果您需要能够快速更换父母,我认为您需要将父信息保存为链接列表。但是,您可以使用存储过程仅使用一次数据库往返来执行此查询操作。
答案 1 :(得分:2)
至少Oracle可以做hierarchical queries。考虑db用户角色的示例:
CREATE TABLE my_dba_role_privs(
grantee VARCHAR2(30),
granted_role VARCHAR2(30)
);
-- assigning roles to roles
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CLIENT', 'SELECT_ORDERS');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('COMMERCIAL_DEP', 'CREATE_ORDERS');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('COMMERCIAL_DEP', 'CLIENT');
-- assigning roles to users
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CL_MATT', 'CLIENT');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CL_JOHN', 'CLIENT');
INSERT INTO my_dba_role_privs( grantee, granted_role ) VALUES('CM_MARY', 'COMMERCIAL_DEP');
现在选择用户'CM_MARY'的所有角色:
SELECT DISTINCT GRANTED_ROLE role_name
FROM my_dba_role_privs
START WITH GRANTEE = 'CM_MARY'
CONNECT BY GRANTEE = PRIOR GRANTED_ROLE;
结果:
COMMERCIAL_DEP
CREATE_ORDERS
CLIENT
SELECT_ORDERS
选择拥有“CLIENT”角色的所有角色和用户
SELECT GRANTEE role_name
FROM my_dba_role_privs
START WITH GRANTED_ROLE = 'CLIENT'
CONNECT BY GRANTED_ROLE = PRIOR GRANTEE;
结果:
CL_JOHN
CL_MATT
COMMERCIAL_DEP
CM_MARY
<强>更新强>
既然你提到过,树会非常静态,尝试Joe Celko's Trees(aprox 180行读取)可能会很有趣。
它根本不需要自联接!所以,我希望它的执行速度比CONNECT BY快。虽然我刚刚在30分钟前阅读过它,但不知道它在现实世界中的表现有多好
Update2:“嵌套集模型”:Managing Hierarchical Data in MySQL这与上面的Joe Celko的树相同,但有更多示例和解释。