我有一个表,表示组织层次结构的传递闭包(即,它是一个单根的树):
create table ancestry (
ancestor integer,
descendant integer,
distance integer
);
我有另一个表,其中包含允许每个用户访问的组织:
create table accessible (
user integer,
organization integer
);
系统向用户显示与用户可以访问的每个组织相关的支出汇总。我总是可以向用户展示公司的视图(即根),向用户显示直接子组织的列表以及他的组织对总数的贡献。在大多数情况下,会有一个孩子,并且在看到多个孩子之前,用户需要向下钻取几个级别。我更愿意在第一个展示多个孩子的组织(即LCA)开始演示。
对于给定的用户,我可以很容易地找到到root的路径集,但是找不到最常见的祖先。我正在使用postgresql 9.1,但更喜欢与数据库无关的解决方案。在最坏的情况下,我可以将路径拉回到应用程序的代码中并在那里计算LCA。
答案 0 :(得分:2)
我重新审视了这个并开发了以下解决方案。我使用common-table-expression来更容易理解它的运行方式,但可以使用子查询轻松编写。
with
hit (id, count) as (
select
ancestry.ancestor
,count(ancestry.descendant)
from
accessible
inner join ancestry
on accessible.organization = ancestry.descendant
where
accessible.user = @user_id
group by
ancestry.ancestor
)
select
ancestry.descendant as lca
from
hit
inner join ancestry
on ancestry.descendant = hit.id
and ancestry.ancestor = @company_id
order by
hit.count desc
,ancestry.distance desc
limit 1
;
对于层次结构中的每个组织,命中CTE计算从子项到遍历组织的根的路径数。然后,LCA是遍历最多的组织。如果出现平局,离根最远的组织(即最大(距离))是实际的LCA。用一个例子可以很好地说明这一点。
A
|
B
/ \
C D
假设我们希望从上面的树中找到节点C和D的LCA。命中CTE产生以下计数:
Node Count
A 2
B 2
C 1
D 1
主查询添加距离:
Node Count Distance
A 2 0
B 2 1
C 1 2
D 1 2
主查询然后按降序计数和距离
对结果进行排序Node Count Distance
B 2 1
A 2 0
C 1 2
D 1 2
LCA是清单中的第一项。
答案 1 :(得分:0)
只是预感而不是db不可知(SQL Server)但适应性强
SELECT TOP 1
a1.ancestor
FROM ancestor a1
INNER JOIN
ancestor a2 ON a1.ancestor=a2.ancestor
WHERE a1.descendent = @Dec1
AND
a2.descendent = @Dec2
ORDER BY a1.distance DESC
如果你想在SQLFiddle中放一些数据,我可以玩它。