【问题标题】:SQL hierarchy count totals reportSQL 层次结构计数总计报告
【发布时间】:2014-12-16 16:18:23
【问题描述】:

我正在使用 SQL Server 2012 和 Report Builder 创建一个报告,该报告必须显示每个父元素的高、中和低级别的风险总数。

每个元素都包含一定数量的风险等级。我需要父元素的总数。总数将包括所有子元素的数量以及元素本身可能拥有的数量。

我在查询中使用 CTE - 我附加的代码不起作用(没有错误 - 它只是显示不正确的结果)并且我不确定我的逻辑是否正确?

希望有人可以提供帮助。提前致谢。

我的表结构是:

元素表

ElementTableId(PK) ElementName ElementParentId

风险表

RiskId(PK) 风险名称 RiskRating ElementId(FK)

我的查询:

WITH cte_Hierarchy(ElementId, ElementName, Generation, ParentElementId)
     AS (SELECT ElementId,
                NAME,
                0,
                ParentElementId
         FROM   Extract.Element AS FirtGeneration
         WHERE  ParentElementId IS NULL
         UNION ALL
         SELECT NextGeneration.ElementId,
                NextGeneration.NAME,
                Parent.Generation + 1,
                Parent.ElementId
         FROM   Extract.Element AS NextGeneration
                INNER JOIN cte_Hierarchy AS Parent
                        ON NextGeneration.ParentElementId = Parent.ElementId),
     CTE_HighRisk
     AS (SELECT r.ElementId,
                Count(r.RiskId) AS HighRisk
         FROM   Extract.Risk r
         WHERE  r.RiskRating = 'High'
         GROUP  BY r.ElementId),
     CTE_LowRisk
     AS (SELECT r.ElementId,
                Count(r.RiskId) AS LowRisk
         FROM   Extract.Risk r
         WHERE  r.RiskRating = 'Low'
         GROUP  BY r.ElementId),
     CTE_MedRisk
     AS (SELECT r.ElementId,
                Count(r.RiskId) AS MedRisk
         FROM   Extract.Risk r
         WHERE  r.RiskRating = 'Medium'
         GROUP  BY r.ElementId)
SELECT rd.ElementId,
       rd.ElementName,
       rd.ParentElementId,
       Generation,
       HighRisk,
       MedRisk,
       LowRisk
FROM   cte_Hierarchy rd
       LEFT OUTER JOIN CTE_HighRisk h
                    ON rd.ElementId = h.ElementId
       LEFT OUTER JOIN CTE_MedRisk m
                    ON rd.ElementId = m.ElementId
       LEFT OUTER JOIN CTE_LowRisk l
                    ON rd.ElementId = l.ElementId
WHERE  Generation = 1 

编辑:

样本数据

ElementTableId(PK) -- ElementName -- ElementParentId
1 ------------------- Main --------------0
2 --------------------Element1-----------1
3 --------------------Element2 ----------1
4 --------------------SubElement1 -------2

RiskId(PK) RiskName RiskRating ElementId(FK)
a -------- Financial -- High -----  2
b -------- HR --------- High -----  3
c -------- Marketing -- Low ------- 2
d -------- Safety -----Medium ----- 4

样本输出:

Element Name   High   Medium   Low  
Main ---------- 2 ---- 1 -------1

【问题讨论】:

  • 您说您拥有的代码不起作用是什么意思?你有错误吗?
  • @TabAlleman 查询显示不正确的结果 - 没有错误消息
  • 它显示什么结果,和你想要的有什么不同?
  • @taballeman 它没有显示每个父母及其子女的总数。它只显示父级本身的总数 - 不包括所有子级结果
  • 添加样本数据和所需的输出

标签: sql sql-server count parent-child hierarchy


【解决方案1】:

这是您的示例表

SELECT * INTO #TABLE1
FROM
(    
    SELECT 1 ElementTableId, 'Main' ElementName ,0 ElementParentId
    UNION ALL
    SELECT 2,'Element1',1
    UNION ALL
    SELECT 3, 'Element2',1
    UNION ALL
    SELECT 4, 'SubElement1',2
)TAB

SELECT * INTO #TABLE2
FROM
(    
    SELECT 'a' RiskId, 'Fincancial' RiskName,'High' RiskRating ,2 ElementId
    UNION ALL
    SELECT 'b','HR','High',3
    UNION ALL
    SELECT 'c', 'Marketing','Low',2
    UNION ALL
    SELECT 'd', 'Safety','Medium',4
)TAB

我们正在查找父级的子级,其计数为HighMediumLow,并使用cross join 显示父级及其子级HighMedium 和@ 的所有组合987654331@

更新

以下变量可用于动态访问记录。

DECLARE @ElementTableId INT;
--SET @ElementTableId = 1

并在查询中使用上述变量

;WITH CTE1 AS
(
     SELECT *,0 [LEVEL]  FROM #TABLE1 WHERE ElementTableId = @ElementTableId
     UNION ALL
     SELECT E.*,e2.[LEVEL]+1  FROM #TABLE1 e 
     INNER JOIN CTE1 e2 on e.ElementParentId = e2.ElementTableId
     AND E.ElementTableId<>@ElementTableId
)
,CTE2 AS
(
    SELECT E1.*,E2.*,COUNT(RiskRating) OVER(PARTITION BY RiskRating) CNT 
    from CTE1 E1
    LEFT JOIN #TABLE2 E2 ON E1.ElementTableId=E2.ElementId  
)
,CTE3 AS
(
    SELECT DISTINCT T1.ElementName,C2.RiskRating,C2.CNT  
    FROM #TABLE1  T1
    CROSS JOIN CTE2 C2
    WHERE T1.ElementTableId = @ElementTableId
)
SELECT *
FROM CTE3
PIVOT(MIN(CNT)
      FOR RiskRating IN ([High], [Medium],[Low])) AS PVTTable

结果

更新 2

我正在根据您的新要求进行更新

这是我添加了额外数据进行测试的示例表

SELECT * INTO #ElementTable
FROM
(    
    SELECT 1 ElementTableId, 'Main' ElementName ,0 ElementParentId
    UNION ALL
    SELECT 2,'Element1',1
    UNION ALL
    SELECT 3, 'Element2',1
    UNION ALL
    SELECT 4, 'SubElement1',2
    UNION ALL
    SELECT 5, 'Main 2',0
    UNION ALL
    SELECT 6, 'Element21',5
    UNION ALL
    SELECT 7, 'SubElement21',6
    UNION ALL
    SELECT 8, 'SubElement22',7
    UNION ALL
    SELECT 9, 'SubElement23',7
)TAB

SELECT * INTO #RiskTable
FROM
(    
    SELECT 'a' RiskId, 'Fincancial' RiskName,'High' RiskRating ,2 ElementId
    UNION ALL
    SELECT 'b','HR','High',3
    UNION ALL
    SELECT 'c', 'Marketing','Low',2
    UNION ALL
    SELECT 'd', 'Safety','Medium',4
    UNION ALL
    SELECT 'e' , 'Fincancial' ,'High'  ,5 
    UNION ALL
    SELECT 'f','HR','High',6
    UNION ALL
    SELECT 'g','HR','High',6
    UNION ALL
    SELECT 'h', 'Marketing','Low',7
    UNION ALL
    SELECT 'i', 'Safety','Medium',8
    UNION ALL
    SELECT 'j', 'Safety','High',8
)TAB

我已经在查询中写了逻辑

;WITH CTE1 AS
(
     -- Here you will find the level of every elements in the table
     SELECT *,0 [LEVEL] 
     FROM #ElementTable WHERE ElementParentId = 0
     UNION ALL
     SELECT ET.*,CTE1.[LEVEL]+1 
     FROM #ElementTable ET 
     INNER JOIN CTE1 on ET.ElementParentId = CTE1.ElementTableId  
)
,CTE2 AS
(
    -- Filters the level and find the major parant of each child
    -- ie, 100->150->200, here the main parent of 200 is 100 
    SELECT *,CTE1.ElementTableId MajorParentID,CTE1.ElementName MajorParentName  
    FROM CTE1 WHERE [LEVEL]=1
    UNION ALL
    SELECT CTE1.*,CTE2.MajorParentID,CTE2.MajorParentName  
    FROM CTE1  
    INNER JOIN CTE2 on CTE1.ElementParentId = CTE2.ElementTableId
)
,CTE3 AS
(
    -- Since each child have columns for main parent id and name, 
    -- you will get the count of each element corresponding to the level you have selected directly
    SELECT DISTINCT CTE2.MajorParentName,RT.RiskRating ,
    COUNT(RiskRating) OVER(PARTITION BY MajorParentID,RiskRating) CNT 
    FROM CTE2 
    JOIN #RiskTable RT ON CTE2.ElementTableId=RT.ElementId  
)
SELECT MajorParentName, ISNULL([High],0)[High], ISNULL([Medium],0)[Medium],ISNULL([Low],0)[Low]
FROM CTE3
PIVOT(MIN(CNT)
      FOR RiskRating IN ([High], [Medium],[Low])) AS PVTTable

【讨论】:

  • 嗨@sarah avanavu 感谢一百万您的帮助。这看起来很棒。但是,如果不包含声明 ReviewId=1 的 WHERE 语句,我将如何获得相同的结果。我想包含的唯一一种 WHERE 语句是说明这些元素来自哪个层次结构的生成/级别
  • 我没听懂你。你能提供更新要求的样本数据吗? @chestternutt
  • ReviewId 在哪里? @chestternutt
  • 我已经修改了查询。随时要求任何更改@chestternutt
  • 抱歉,Sarath,我的意思是 ElementTableId!报告需要是动态的,所以我不想输入 ElementTableId,因为这是一个内部值。我需要输入我想查看总数的级别/世代
猜你喜欢
  • 2013-02-09
  • 2023-03-09
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多