2010-12-07 8 views
0

私は再帰的なCTEを使用して自己参照の従業員テーブルを拡張し、ユーザーと重大度で集計された欠陥の結果セットを構築するSQLを持っています。ロールアップロジックを持つ再帰的なSQL関数?

SELECT e.FullName, Urgent, High, Medium, Low 
FROM fnGetEmployeeHierarchyByUsername ('ssalvati') e 
LEFT OUTER JOIN(
    SELECT [AssignedTo], 
      SUM([1-Urgent]) AS Urgent, 
      SUM([2-High]) AS High, 
      SUM([3-Medium]) AS Medium, 
      SUM([4-Low]) AS Low 
     FROM (SELECT [AssignedTo],[BusinessSeverity] FROM Defects WHERE Status <> 'Closed') D 
    PIVOT (COUNT([BusinessSeverity]) FOR [BusinessSeverity] IN ([1-Urgent],[2-High],[3-Medium],[4-Low])) V 
    GROUP BY [AssignedTo]) AS def 
ON e.ntid = def.[AssignedTo] 

iがPARAMとしてユーザー名をとり、生成豚肉を持つようにしたい:ここ

ALTER FUNCTION [dbo].[fnGetEmployeeHierarchyByUsername] 
( 
    @NTID varchar(100) = null 
) 
RETURNS TABLE 
AS 
RETURN 
( 
    WITH yourcte AS 
    ( 
    SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName--, Name 
    FROM Employees 
    WHERE NTID = @NTID 
    UNION ALL 
    SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName--, e.Name 
    FROM Employees e 
    JOIN yourcte y ON e.ManagerNTID = y.NTID 
) 
SELECT EmployeeId, ManagerID, NTID, FullName--, Name 
FROM yourcte 
) 

は、ユーザーによって欠陥を集約するための私のSQLです:ここ

は私のCTEであります上記のSQLのような2つの拡張機能の結果:

  1. これは、パラメータとして渡されたユーザーをリストするために必要です結果セットの最初のレコードとしてリストされます。

  2. マネージャに報告する従業員は、1つのレベルしか表示せず、フルツリーを表示しないようにする必要があります。最初のレベルは、すべてのレベル1のユーザーにロールアップされた人に割り当てられている根本的な欠陥のロールアップでなければなりません。言い換えれば、今のようにマネージャーの下にツリー全体を表示する必要はありません。私は1つのレベルだけを表示する必要がありますが、すべてのレベルの欠陥の合計が必要です。

アイデア?

答えて

0

ここではそれを行う長いダミーの方法です。私はそれが働いているが、ソリューションははるかに良い可能性があります。私は誰かがこれを行うSQL2005の方法を投稿することを期待しています...

alter PROC sel_DefectReportByManagerNTID_rollup 
(@ManagerNTID NVARCHAR(100))  
AS 

CREATE TABLE #DefectCounts 
(
id INT IDENTITY(1, 1) , 
MgrRolledInto NVARCHAR(100) NULL, 
AltBusinessSeverity NVARCHAR(100) NULL, 
DefectCount INT NULL 
); 


CREATE TABLE #directReports 
(
pk INT IDENTITY(1, 1) , 
directReportNTID NVARCHAR(100) NULL 
); 

INSERT INTO #directReports 
SELECT NTID FROM Employees WHERE ManagerNTID = @ManagerNTID 
--select * from #directReports 

DECLARE @maxPK INT; 
SELECT @maxPK = MAX(PK) FROM #directReports 

DECLARE @pk INT; 
SET @pk = 1 


INSERT INTO #DefectCounts (MgrRolledInto,AltBusinessSeverity,DefectCount) 
SELECT @ManagerNTID, d.AltBusinessSeverity, COUNT(*) 
     FROM Defects d 
      JOIN StatusCode C ON C.CodeName = d.Status AND c.scid = 10 
     WHERE d.AssignedTo = @ManagerNTID 
     GROUP BY d.AltBusinessSeverity 


WHILE @pk <= @maxPK 
BEGIN 
    /* Get one direct report at a time to aggregate their defects under them... */ 
    DECLARE @dirRptNTID NVARCHAR(100); 
    SET @dirRptNTID = (SELECT directReportNTID 
         FROM #directReports 
         WHERE PK = @pk) 


    INSERT INTO #DefectCounts (MgrRolledInto,AltBusinessSeverity,DefectCount) 
     SELECT @dirRptNTID, d.AltBusinessSeverity, COUNT(*) 
     FROM Defects d 
      JOIN StatusCode C ON C.CodeName = d.Status AND c.scid = 10 
      JOIN (SELECT * FROM fnGetEmployeeHierarchyByUsername(@dirRptNTID)) emp ON emp.NTID = d.AssignedTo 
     WHERE d.AssignedTo IS NOT NULL 
     GROUP BY d.AltBusinessSeverity 

    SELECT @pk = @pk + 1 
END 



SELECT e.FullName,  
    isnull(Urgent,0) as Urgent,  
    isnull(High,0) as High,  
    isnull(Medium,0) as Medium,  
    isnull(Medium3000,0) as Medium3000,  
    isnull(Low,0) as Low  
FROM ( select * from fnGetEmployeeHierarchyByUsername (@ManagerNTID) where depth <= 1) e  
left outer join (
        SELECT MgrRolledInto,  
          SUM([1-Urgent]) AS Urgent,  
          SUM([2-High]) AS High,  
          SUM([3-Medium]) AS Medium,  
          SUM([3-Medium (3000)]) AS Medium3000, 
          SUM([4-Low]) AS Low  
        FROM #DefectCounts dfs 
        PIVOT 
        (sum(DefectCount) FOR AltBusinessSeverity IN ([1-Urgent],[2-High],[3-Medium],[3-Medium (3000)],[4-Low])) V  
        GROUP BY MgrRolledInto 
       ) def_data on def_data.MgrRolledInto = e.NTID 
order by e.depth 
+0

これはその仕組みです。 – kacalapy

0

あなたは深さ、すなわち

WITH yourcte AS 
    ( 
    SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName, 0 AS Depth 
    FROM Employees 
    WHERE NTID = @NTID 
    UNION ALL 
    SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName, y.Depth + 1 
    FROM Employees e 
    JOIN yourcte y ON e.ManagerNTID = y.NTID 
) 

(入力パラメータで、ユーザが深さゼロであるべきな)あなたはその後、深さによって、あなたの出力を注文することができますが含まれるように、あなたのCTEを変更した場合。これを使用するあなたも、私はあなたの上に追加SQLで

に深さ> = 1


編集あなたが戻るの深さと集約欠陥を制限することができるはず、基本的にすべての欠陥をロールアップしたいですレベル1のユーザーですか?だから、このレベルのユーザーのNTIDは、以下のCTEに深さ> = 1ですべてのレコードの項目で別の編集グループになり、あなたが/ rollup

WITH yourcte AS 
    ( 
    SELECT EmployeeId, ManagerNTID, ManagerID, NTID 
      ,FullName, 0 AS Depth, NTID as GroupingID 
    FROM Employees 
    WHERE NTID = @NTID 
    UNION ALL 
    SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID 
      ,e.FullName, y.Depth + 1, CASE 
             WHEN y.Depth + 1 = 1 THEN e.NTID 
             ELSE y.GroupingId 
            END 
    FROM Employees e 
    JOIN yourcte y ON e.ManagerNTID = y.NTID 
) 
+0

私はどのようにレベル1のデータの残りの部分をロールアップするのですか? – kacalapy

+0

元の回答への編集を参照してください –

+0

私は深さとその働きを追加しました - ありがとう。しかし、私はまだロールアップを動作させる方法については混乱しています。それは第2のCTEですか?私は、すべてのレベル1のレコードをそれらの下のすべての子レベルのロールアップ(合計)にします。レコードがレベル1の場合、その下に3つのレベルがあり、その合計値は – kacalapy

1
によってグループに使用できるGROUPINGIDとしてNTIDを追加

ここにはmssqlのインストールやデータはありませんので、これはテストされていませんが、一般的に正しいと思うし、少なくともあなたを役に立つ方向に押し進めるべきだと思います。

まず、UDFのクエリを変更して、2つの追加情報を提供する必要があります。あなたの集約が崩壊する「一番上の」従業員(私があなたが言ったのは、最初の直接の報告書であり、トップの従業員ではないと思う)と全体の深さ。そのように:

WITH yourcte AS 
    ( 
    SELECT EmployeeId, ManagerNTID, ManagerID, NTID, FullName, 0 as Depth, ntid as Topmost 
    FROM Employees 
    WHERE NTID = @NTID 
    UNION ALL 
    SELECT e.EmployeeId, e.ManagerNTID, e.ManagerID, e.NTID, e.FullName, y.Depth+1, case when y.depth = 0 then e.ntid else y.Topmost end 
    FROM Employees e 
    JOIN yourcte y ON e.ManagerNTID = y.NTID 
) 
SELECT EmployeeId, ManagerID, NTID, FullName, Depth, Topmost 
FROM yourcte 

はその後、あなたの実際のクエリは、いくつかの余分な詳細を必要としたいことがありので、あなたのUDFへの二重の呼び出しは少し高価かもしれないという情報を抽出し、それ

SELECT 
    e.FullName, 
    Urgent, 
    High, 
    Medium, 
    Low 
FROM fnGetEmployeeHierarchyByUsername ('ssalvati') e 
LEFT OUTER JOIN(
    SELECT [AssignedTo], 
      SUM([1-Urgent]) AS Urgent, 
      SUM([2-High]) AS High, 
      SUM([3-Medium]) AS Medium, 
      SUM([4-Low]) AS Low 
     FROM (SELECT [AssignedTo],[BusinessSeverity] FROM Defects WHERE Status <> 'Closed') D 
     join fnGetEmployeeHierarchyByUsername ('ssalvati') e2 on d.AssignedTo = e2.ntid 
    PIVOT (COUNT([BusinessSeverity]) FOR [BusinessSeverity] IN ([1-Urgent],[2-High],[3-Medium],[4-Low])) V 
    where e2.TopMost = e.ntid 
    GROUP BY [AssignedTo]) AS def 
ON e.ntid = def.[AssignedTo] 
where e.Depth <= 1 

を使用するにはこれをsprocに入れ、一時テーブルを使ってUDFの結果をキャッチすることを検討してください。

また、UDFは「最上位」の深さに関する追加のパラメータを取ることができるので、これは現在のハードコーディングされた形式になっています。

+1

です。このソリューションをテストして、そのケースを後方に見つけたようです... y.depth = 0 then y.Topmost else e.ntid end " – kacalapy

+0

1エラー... メッセージ4104、レベル16、状態1、行1 マルチパート識別子" e2.TopMost "はバインドできませんでした。 メッセージ4104、レベル16、状態1、行1 マルチパート識別子 "e.ntid"はバインドできませんでした。 – kacalapy

関連する問題