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

时间:2017-04-30 12:52:37

标签: sql database teradata

我希望获得每个数据库的空间使用量以及所有子孙的总和......

在Teradata中,数据库按照数据库及其直接所有者的层次结构进行组织。 每个数据库都有MaxPerm(=允许的空间使用)和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的总和。但是,如果我添加一个级别,让我们说使用user1拥有的其他数据库,我必须添加一个额外的级别。添加级别或连接的数据库名称在汇总中不起作用(至少我没有使它工作)。我想要该级别中每个名字的总和。

最终目标是按组概述空间使用情况,这些组位于层次结构中的不同级别。如果将user1移动到DBC-> GroupSpace-&gt; Group7-&gt; Project1-&gt; Subproject5-&gt; SandBox,则SQL仍然可以工作。 我希望能够回答有关Group7中整体和详细空间使用情况的问题

1 个答案:

答案 0 :(得分:1)

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;