Oracle在整个树上具有条件的分层查询

时间:2014-09-12 16:55:13

标签: sql oracle11g tree hierarchical-data

我需要使用分层(或其他)查​​询来选择树形结构数据,其中必须为整个树保持特定条件(即全部树中的节点)。

这意味着如果树的单个节点违反了条件,则根本不会选择树(即使该树的其他节点也不符合条件,因此抛弃完整的树)。

此外,我想选择所有树 - 这些树的所有节点,其中条件适用于每个节点(即,不仅选择一个这样的树,而是选择所有这些树)。


编辑:

考虑这个通过parent_id列相互连接的文件表示例,以便它们形成树。还有一个外键owner_id,它引用其他表主键。

PK file_id | name | parent_id | owner_id
----------------------------------------
   1       | a1   | null      | null                 -- root of one tree
   2       | b1   | 1         | null
   3       | c1   | 1         | null
   4       | d1   | 2         | 100
   5       | a2   | null      | null                 -- root of another tree
   6       | b2   | 5         | null
   7       | c2   | 6         | null
   8       | d2   | 7         | null

列parent_id对file_id列有一个外键约束(构成层次结构)。

还有一个表(让我们称之为联结表),其中(除其他外)外键file_ids以多对一关系存储到上述文件表中:

FK file_id | other data
-----------------------
   1       | ...
   1       | ...
   3       | ...

现在我需要的查询是选择所有这样的整个文件树,其中满足以下条件的树中的每个文件:

  • 文件的owner_id为空
  • 并且该文件在联结表中没有相关记录(没有通过file_id FK引用该文件的记录)

对于上面的示例,查询应该导致:

file_id | name | parent_id | owner_id
---------------------------------------
5       | a2   | null      | null
6       | b2   | 1         | null
7       | c2   | 1         | null
8       | d2   | 2         | null

所有节点都在表中创建一个完整的树(没有丢失子节点或父节点),并且每个节点都符合上述条件(在连接表中没有所有者且没有关系)。

1 个答案:

答案 0 :(得分:1)

这将生成具有简单分层查询的树 - 实际上只需要为每行建立根file_id - 同时加入junction以检查那里的记录。这可以得到重复,这在那个阶段是可以的。然后将max()的分析版本应用于中间结果集,以确定是否满足具有相同根的任何行的条件:

select file_id, name, parent_id, owner_id
from (
  select file_id, name, parent_id, owner_id,
    max(j_id) over (partition by root_id) as max_j_id,
    max(owner_id) over (partition by root_id) as max_o_id
  from (
    select f.*, j.file_id as j_id,
      connect_by_root f.file_id as root_id
    from files f
    left outer join junction j
    on j.file_id = f.file_id
    connect by prior f.file_id = f.parent_id
    start with f.parent_id is null
  )
)
where max_j_id is null
and max_o_id is null
order by file_id;

 FILE_ID   NAME   PARENT_ID   OWNER_ID 
--------- ------ ----------- ----------
        5     a2      (null)     (null) 
        6     b2           5     (null) 
        7     c2           6     (null) 
        8     d2           7     (null) 

最里面的查询获取根和任何匹配的联结记录(带有重复项)。下一级添加分析最大所有者和结点值(如果有),为同一根的每一行提供相同的结果。外部查询然后筛选出任何具有任何行值的行。

SQL Fiddle