如何计算层次结构所有级别的总和

How to calculate a sum for all levels of a a hierarchy

我想得到Space-每个数据库的使用情况以及所有子孙的总和...

在 Teradata 中,数据库按照数据库及其直接所有者的层次结构进行组织。 每个数据库都有其 MaxPerm(=允许 space 使用)和 CurrentPerm(=实际使用的)

到目前为止我有以下内容: 分两步做,先拉平层级,再用rollup

总结
create volatile table dbHierarchy as
(
    WITH RECURSIVE dbs AS
    (
        SELECT
              cast(databasename AS VARCHAR(500)) AS L0
            , cast('' AS VARCHAR(500)) AS L1
            , cast('' AS VARCHAR(500)) AS L2
            --, cast(null AS VARCHAR(500)) AS L3
            , ownername
            , databasename
            , 0 AS depth
            --, CAST(DatabaseName AS VARCHAR(500)) AS pretty_hierarchy
        FROM DBC.databasesv
        WHERE DatabaseName = 'DBC'

        UNION ALL

        SELECT
              L0
            , case when dbs.depth = 0 then dbsv.DatabaseName else dbs.L1  end  as L1
            , case when dbs.depth = 1 then dbsv.DatabaseName else dbs.L2  end  as L2
            --,case when dbs.depth = 2 then dbsv.DatabaseName else dbs.L3  end  as L3
            , dbsv.ownername
            , dbsv.databasename
            , depth + 1 AS depth
            --, pretty_hierarchy || substring('            ' FROM 1 FOR (dbs.depth + 1)*3) ||'>'|| dbsv.DatabaseName  as pretty_hierarchy
        FROM dbs
        INNER JOIN "DBC".DatabasesV dbsv
            ON dbsv.OwnerName = dbs.databasename
            AND dbsv.DatabaseName <> dbs.databasename
        WHERE dbs.depth <=10
    )
    SELECT * FROM dbs
) WITH DATA
PRIMARY INDEX (databasename)
ON COMMIT PRESERVE ROWS;

select
      coalesce(L0,'sum') as L0
    , coalesce(L1,'sum') as L1
    , coalesce(L2,'sum') as L2
    --, coalesce(L3,'sum') as L3
    ,SUM(Space.MaxPerm)/(1024*1024)(bigint)  as Max_Perm
    ,SUM(Space.CurrentPerm)/(1024*1024) (bigint) as Current_Perm
from DBC.DiskSpace Space
    inner join dbHierarchy Hir
    on Space.databasename = Hir.databasename
    group by rollup (L0,L1,L2) --(L0, L1,L2,L3)
    order by L0, L1, L2 --, L3
;

到目前为止还不错,但不知何故受到固定级别数的限制。 我可以根据实际用例自定义它(根据找到的层次结构的实际深度添加级别)。

是否有一种不同的方法可以适应层次结构的深度?

实际输出为

sum;sum;sum;37780;301
DBC;sum;sum;37780;301
DBC;;sum;34369;125
DBC;;;34369;125
DBC;All;sum;0;0
DBC;All;;0;0
DBC;Crashdumps;sum;71;0
DBC;Crashdumps;;71;0
...
DBC;Samples;sum;1215;159
DBC;Samples;;9;0
DBC;Samples;financial;12;11
DBC;Samples;manufacturing;0;0
DBC;Samples;retail;22;21
DBC;Samples;sandbox;1024;0
DBC;Samples;tpch;52;46
DBC;Samples;transportation;0;0
DBC;Samples;twm_md;76;70
DBC;Samples;twm_results;4;0
DBC;Samples;twm_source;11;9
...
DBC;SysAdmin;sum;1043;2
DBC;SysAdmin;;19;2
DBC;SysAdmin;user1;1024;0

没关系。我得到了 user1 和 Samples 的总和。但是如果我添加一个级别,比方说用户 1 拥有的其他数据库,我必须添加一个额外的级别。添加级别或连接的数据库名称在汇总中不起作用(至少我没有让它起作用)。我想要该级别中每个名称的总和。

最终目标是概述 space 组的使用情况,这些组位于层次结构中的不同级别。如果将 user1 移动到 DBC->GroupSpace->Group7->Project1->Subproject5->SandBox,SQL 应该仍然有效。 我希望能够回答有关 Group7

中总体和详细 space 使用情况的问题

dbc.ChildrenV 将层次结构解析为每个 parent/child 一行,这就是我用来为所有数据库及其子级计算 Current/MaxPerm 的方法:

WITH DBSpace AS 
 ( -- PermSpace for each database
   SELECT
      DatabaseName
     ,Sum(MaxPerm) AS MaxPerm
     ,Sum(CurrentPerm) AS CurrentPerm
   FROM dbc.DiskSpaceV
   GROUP BY DatabaseName
 )
SELECT
   DBSpace.DatabaseName
  ,DBSpace.MaxPerm
  ,DBSpace.CurrentPerm
  ,ChildSpace.ChildrenCount
  ,ChildSpace.ChildrenMaxPerm
  ,ChildSpace.ChildrenCurrentPerm
  ,DBSpace.CurrentPerm + Coalesce(ChildSpace.ChildrenCurrentPerm,0)
FROM DBSpace
LEFT JOIN
 ( -- PermSpace for all children of a database
   SELECT
      ch.Parent
     ,Sum(sp.MaxPerm) AS ChildrenMaxPerm
     ,Sum(sp.CurrentPerm) AS ChildrenCurrentPerm
     ,Count(*)
        -- 4 rows (all/dbc/default/public) for parent = dbc are missing in dbc.Children:
      + CASE WHEN ch.Parent = 'dbc' THEN 4 ELSE 0 END AS ChildrenCount
   FROM
      dbc.ChildrenV AS ch 
   JOIN DBSpace AS sp
     ON ch.Child = sp.DatabaseName
   GROUP BY ch.Parent
 ) AS ChildSpace
ON DBSpace.DatabaseName = ChildSpace.Parent
-- uncomment to return only databases with PermSpace
-- WHERE ChildrenMaxPerm > 0 OR MaxPerm > 0;

您可以将其加入递归查询以按正确顺序显示层次结构(EXTUSER 将丢失,但这只是一个虚拟对象):

WITH RECURSIVE cte (DatabaseName, Path, LEVEL) AS
 (
   SELECT Trim(DatabaseName)
          ,DatabaseName(VARCHAR(600))
          ,0 (BYTEINT)
   FROM   dbc.DatabasesV AS d
   WHERE  DatabaseName = 'dbc'

   UNION ALL

   SELECT Trim(d.DatabaseName)
          ,cte.Path || '.' || Trim(d.DatabaseName)
          ,LEVEL + 1
   FROM   dbc.DatabasesV AS d
          ,cte
   WHERE  d.OwnerName = cte.DatabaseName
   AND    d.DatabaseName <> d.OwnerName
   AND    LEVEL < 20
 )
,DBSpace AS 
 ( -- PermSpace for each database
   SELECT
      DatabaseName
     ,Sum(MaxPerm) AS MaxPerm
     ,Sum(CurrentPerm) AS CurrentPerm
   FROM dbc.DiskSpaceV
   GROUP BY DatabaseName
 )
SELECT LEVEL
       ,Substring(Cast('' AS CHAR(60)) FROM 1 FOR LEVEL * 2)  || cte.DatabaseName AS Hierarchy
       ,AllSpaces.*
FROM cte JOIN 
 (
   SELECT
      DBSpace.DatabaseName
     ,DBSpace.MaxPerm
     ,DBSpace.CurrentPerm
     ,Coalesce(ChildSpace.ChildrenCount, 0) AS ChildrenCount
     ,ChildSpace.ChildrenMaxPerm
     ,ChildSpace.ChildrenCurrentPerm
   FROM DBSpace
   LEFT JOIN
    ( -- PermSpace for all children of a database
      SELECT
         ch.Parent
        ,Sum(sp.MaxPerm) AS ChildrenMaxPerm
        ,Sum(sp.CurrentPerm) AS ChildrenCurrentPerm
        ,Count(*)
           -- 4 rows (all/dbc/default/public) for parent = dbc are missing in dbc.Children:
         + CASE WHEN ch.Parent = 'dbc' THEN 4 ELSE 0 END AS ChildrenCount
      FROM
         dbc.ChildrenV AS ch 
      JOIN DBSpace AS sp
        ON ch.Child = sp.DatabaseName
      GROUP BY ch.Parent
    ) AS ChildSpace
   ON DBSpace.DatabaseName = ChildSpace.Parent
 ) AS AllSpaces
  ON cte.DatabaseName = AllSpaces.DatabaseName
-- uncomment to return only databases with PermSpace
-- WHERE ChildrenMaxPerm > 0 OR MaxPerm > 0
ORDER BY Path;