【问题标题】:Hierarchical query rollup Rollup分层查询汇总 Rollup
【发布时间】:2014-04-27 19:13:11
【问题描述】:

我有下表:

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 查询,但函数也是可以的。

我尝试将分层查询与汇总 (sql 2008 r2) 混合使用,但到目前为止没有成功。

请指教。

【问题讨论】:

    标签: tsql hierarchical rollup


    【解决方案1】:

    这个 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 
    

    【讨论】:

      【解决方案2】:

      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)
      

      【讨论】:

        猜你喜欢
        • 2011-07-27
        • 1970-01-01
        • 2018-02-02
        • 1970-01-01
        • 1970-01-01
        • 2013-12-21
        • 2021-12-08
        • 1970-01-01
        • 2021-12-25
        相关资源
        最近更新 更多