确定分层路径的子计数

时间:2011-01-29 10:45:44

标签: sql postgresql

我有一个由以下列组成的表:

child_count | path
------------+-----
            | /
            | /a
            | /a/a
            | /a/b
            | /a/b/c
            | /b

目前,只有路径列有数据。我想知道一个SQL(最好是PostgreSQL)查询,它能够确定每个路径的子计数,如下所示:

child_count | path
------------+-----
2           | /
2           | /a
0           | /a/a
1           | /a/b
0           | /a/b/c
0           | /b

2 个答案:

答案 0 :(得分:1)

你可以用以下方法计算路径的深度:

len(path) - len(replace(path,'/','')) 

然后孩子的深度比父母多一个,孩子的路径从父路径开始:

on      children.depth = parents.depth + 1
        and substring(children.path, 1, len(parents.path)) = parents.path

将它们放在一起(对于SQL Server,但应该对Postgres进行微小更改):

;with depth as 
        (
select  depth = case when path = '/' then 0 
                     else len(path) - len(replace(path,'/','')) 
                end
,       path
from    YourTable
        )
select  COUNT(children.path) as child_count
,       parents.path
from    depth parents
left join
        depth children
on      children.depth = parents.depth + 1
        and substring(children.path, 1, len(parents.path)) = parents.path
group by    
        parents.path

打印:

child_count path                
----------- --------------------
2           /                   
2           /a                  
0           /a/a                
1           /a/b                
0           /a/b/c              
0           /b                  

测试数据:

if OBJECT_ID('YourTable') is not null
    drop table YourTable
create table YourTable (child_count int, path varchar(max))
insert YourTable (path) values
('/'),
('/a'),
('/a/a'),
('/a/b'),
('/a/b/c'),
('/b')

答案 1 :(得分:1)

Andomar在编辑时打败了我,但我会发布我的解决方案,因为它使用了一些PostgreSQL特定的东西。

with path_elements as (
  select path, array_length(string_to_array(path, '/'),1) as element_count
  from path_table
)
select parent_path, count(child_path) 
from (
  select p.path as parent_path,
         c.path as child_path
  from path_elements p
    left join path_elements c 
              on p.element_count + 1 = c.element_count 
             and substring(c.path, 1, length(p.path)) = p.path
) t
group by parent_path
order by parent_path;