I took a fresh look at this and developed the following solution. I used a common-table-expression to make it easier to understand how it operates but it could easily be written using a sub-query.
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
;
The hit CTE counts, for each organization in the hierarchy, the number of paths from a child to the root that traverse the organization. The LCA is then the organization with the most traversals. In the event of a tie, the organization farthest from the root (i.e., max(distance)) is the actual LCA. This is best illustrated with an example.
A
|
B
/ \
C D
Assuming we wish to find the LCA of nodes C and D from the tree above. The hit CTE produces the following counts:
Node Count
A 2
B 2
C 1
D 1
The main query adds the distance:
Node Count Distance
A 2 0
B 2 1
C 1 2
D 1 2
The main query then orders the results by descending count and distance
Node Count Distance
B 2 1
A 2 0
C 1 2
D 1 2
The LCA is the first item in the list.