2010-03-12 5 views
1

J'ai une table de hiérarchie dans SQL Server 2005 qui contient des employés -> managers -> department -> location -> state.Agrégation basée sur la hiérarchie

Table d'échantillons pour la table de hiérarchie:

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 

La deuxième est table de faits qui contient les détails du salaire des employés ID et le salaire.

Données d'échantillons pour la table de fait:

ID Salary 
4  6000 
5  5000 
7  4000 

Est-il un bon moyen d'afficher à la hiérarchie de la table de la hiérarchie avec la somme agrégée de salaire en fonction des employés. Résultat attendu est comme

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 

Dans mon environnement de production, table de hiérarchie peut contenir 23000+ lignes et table de faits peut contenir 300,000+ lignes. Ainsi, j'ai pensé fournir n'importe quel niveau de groupid à la requête pour récupérer seulement ses enfants et sa valeur agrégée correspondante. Une meilleure solution?

Répondre

0

Cette solution produit le résultat correct. Tant que les index sont en place, cela devrait fonctionner correctement avec votre ensemble de données de production, mais je ne l'ai pas testé sur vos données d'exemple.

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