2010-03-12 4 views
1

У меня есть таблица иерархии в SQL Server 2005, в которой содержатся сотрудники -> менеджеры -> отдел -> местоположение -> состояние.Агрегирование на основе иерархии

Пример таблицы для таблицы иерархии:

ID Name   ParentID Type 
1 PA    NULL  0 (group) 
2 Pittsburgh  1   1 (subgroup) 
3 Accounts  2   1 
4 Alex   3   2 (employee) 
5 Robin   3   2 
6 HR    2   1 
7 Robert   6   2 

Второй один является то, таблица, которая содержит данные работника заработной платы ID и зарплата.

Пример данные для таблицы фактов:

ID Salary 
4  6000 
5  5000 
7  4000 

есть ли хорошо способ отображения иерархии из таблицы иерархии с агрегированной суммой заработной платы на основе сотрудников. Ожидаемый результат, как

Name    Salary 
PA    15000 (Pittsburgh + others(if any)) 
    Pittusburgh  15000 (Accounts + HR) 
    Accounts  11000 (Alex + Robin) 
     Alex   6000 (direct values) 
     Robin  5000 
    HR    4000 
     Robert  4000 

В моей производственной среде, иерархия таблица может содержать 23000+ строк и таблица фактов может содержать 300,000+ строки. Итак, я думал о предоставлении любого уровня groupid для запроса, чтобы получить только его дочерние элементы и его соответствующее агрегированное значение. Любое лучшее решение?

ответ

0

Это решение дает правильный результат. Пока индексы на месте, это должно выполнить ОК в отношении вашего производственного набора данных, но я не тестировал его больше, чем ваши данные образца.

DECLARE @tree TABLE 
(ID INT 
,name VARCHAR(15) 
,ParentID INT 
,TYPE TINYINT 
) 

DECLARE @salary TABLE 
(ID INT 
,Salary INT 
) 

INSERT @tree 
     SELECT 1,'PA',NULL,0 
UNION SELECT 2,'Pittsburgh',1,1 
UNION SELECT 3,'Accounts',2,1 
UNION SELECT 4,'Alex',3,2 
UNION SELECT 5,'Robin',3,2 
UNION SELECT 6,'HR',2,1 
UNION SELECT 7,'Robert',6,2 


INSERT @salary 
     SELECT 4,6000 
UNION SELECT 5,5000 
UNION SELECT 7,4000 


;WITH salaryCTE 
AS 
(
     SELECT t.* 
       ,s.Salary 
     FROM  @tree   AS t 
     LEFT JOIN @salary  AS s 
     ON  s.ID = t.ID 
) 
,recCTE 
AS 
(
     SELECT t.ID 
       ,CAST(t.name AS VARCHAR(MAX)) AS name 
       ,t.ParentID 
       ,ISNULL(t.Salary,0) AS Salary 
       ,0 AS LEVEL 
       ,CAST(t.ID AS VARCHAR(100)) AS ord 
     FROM salaryCTE AS t 
     WHERE t.ParentID IS NULL 

     UNION ALL 

     SELECT t.ID 
       ,CAST(REPLICATE(' ',r.LEVEL) + t.name AS VARCHAR(MAX)) AS name 
       ,t.ParentID 
       ,ISNULL(t.Salary,0) AS Salary 
       ,r.LEVEL + 1 
       ,CAST(r.ord + '|' + CAST(t.ID AS VARCHAR(11)) AS VARCHAR(100)) AS ord 
     FROM  salaryCTE  AS t   
     JOIN  recCTE  AS r 
     ON  r.ID = t.ParentID 
) 
SELECT name 
     ,salary 
FROM (  
     SELECT r1.name 
       ,r1.ord 
       ,SUM(r2.salary) AS salary 

     FROM recCTE AS r1 
     LEFT JOIN recCTE AS r2 
     ON r2.ord LIKE r1.ord + '%' 
     GROUP BY r1.name,r1.ord 
    ) AS x 
ORDER BY ord,name 
Смежные вопросы