2014-04-27 186 views
0

我有如下表:層次查詢彙總彙總

parent_id child_id child_class 
1 2 1 
1 3 1 
1 4 2 
2 5 2 
2 6 2 

PARENT_ID代表一個文件夾ID。子id代表子文件夾(其中child_class = 1)或子文件(其中child_class = 2)。

我想通過以下方式只獲得所有文件(child_class = 2)的彙總計數器(自下而上)。例如,如果C是包含5個文件的葉文件夾(沒有子文件夾),B是C文件的父文件夾中有4個文件,則C上的計數器應該表示5,而B上的計數器應該表示爲9(= 5從C加上B中的4個文件等等遞歸地自下而上考慮到兄弟文件夾等。

在上面的例子中,我期望下面的結果(注意3是沒有文件的子文件夾):

parent_id FilesCounter 
3 0 
2 2 
1 3 

我更喜歡SQL查詢的性能,但功能也是可以的。

我試圖混合hirarchical查詢與彙總(SQL 2008 R2)迄今沒有成功。

請指教。

回答

0

這CTE應該做的伎倆...這是SQLFiddle

SELECT parent_id, child_id, child_class, 
(SELECT COUNT(*) FROM tbl a WHERE a.parent_id = e.parent_id AND child_class <> 1) AS child_count 
INTO tbl2 
FROM tbl e 

;WITH CTE (parent_id, child_id, child_class, child_count) 
AS 
(
-- Start with leaf nodes 
    SELECT parent_id, child_id, child_class, child_count 
    FROM tbl2 
    WHERE child_id NOT IN (SELECT parent_id from tbl) 
    UNION ALL 
-- Recursively go up the chain 
    SELECT e.parent_id, e.child_id, e.child_class, e.child_count + d.child_count 
    FROM tbl2 e 
    INNER JOIN CTE AS d 
    ON e.child_id = d.parent_id 
) 
-- Statement that executes the CTE 
SELECT FOLDERS.parent_id, max(ISNULL(child_count,0)) FilesCounter 
FROM (SELECT parent_id FROM tbl2 WHERE parent_id NOT IN (select child_id from tbl2) 
    UNION 
    SELECT child_id FROM tbl2 WHERE child_class = 1) FOLDERS 
LEFT JOIN CTE ON FOLDERS.parent_id = CTE.parent_id 
GROUP BY FOLDERS.parent_id 
0

Zak的答案很接近,但根文件夾沒有很好地彙總。以下工作:

with par_child as (
select 1 as parent_id,    2 as child_id,    1 as child_class 
union all select 1,    3,    1 
union all select 1,    4,    2 
union all select 2,    5,    1 
union all select 2,    6,    2 
union all select 2,    10,   2 
union all select 3,    11,   2 
union all select 3,    7 ,    2 
union all select 5,    8 ,    2 
union all select 5,    9 ,    2 
union all select 5,    12,   1 
union all select 5,    13,   1 
) 
, child_cnt as 
(
     select parent_id as root_parent_id, parent_id, child_id, child_class, 1 as lvl from par_child union all 
     select cc.root_parent_id, pc.parent_id, pc.child_id, pc.child_class, cc.lvl + 1 as lvl from 
     par_child pc join child_cnt cc on (pc.parent_id=cc.child_id) 
), 
distinct_folders as (
select distinct child_id as folder_id from par_child where child_class=1 
) 
select root_parent_id, count(child_id) as cnt from child_cnt where child_class=2 group by root_parent_id 
union all 
select folder_id, 0 from distinct_folders df where not exists (select 1 from par_child pc where df.folder_id=pc.parent_id)