2016-05-09 14 views
4

次の表のように、テーブルCsOrganizationに階層的にデータが格納されたテーブルがあります。SQL Server - 異なるテーブルからのCTE再帰的SUM値

Table Name : CsOrganization 
OrgId OrgParentId OrgName 
1  NULL   X COMPANY 
2  1    Administrator 
3  2    Adm 1 
4  2    Adm 2 
5  3    Adm 1_1 

し、次の表のようにCsOrganizationテーブルに関連EmHisOrganizationという名前のテーブルがあります。

Table Name : EmHisOrganization 
EmpId OrgId  
1  2   
2  2   
3  3  
4  4   
5  5   

各従業員は、彼らが持っている組織に基づいて残業データを持つことになります、そして、彼らはEmOvertimeテーブルに格納されています。

Table Name : EmOvertime 
EmpId TotalOtReal  
1  1.00   
2  2.00   
3  3.00  
4  2.00   
5  1.00 

問題は、私は、各組織に基づいてTotalHoursの合計を取得する必要があります。 TotalHoursの合計は、その子のTotalHoursデータもすべて合計する必要があります。これまでのところ、私は親子を理解することができましたが、別のテーブルからTotalHoursデータを取得して合計する方法はわかりません。私が知る限り、これらのテーブルに参加してTotalHoursを取得する必要がありますが、残念ながらCTE Recursiveでは構文でOUTER JOINを使用できません。 Adm 1のTotalHoursが値を持っているTotalHours列とID 5と従業員では3.00の値を持つID 3との和従業員からである

Desired Output 
OrgId  OrgName  TotalHours  
1   X COMPANY  9.00 
2   Administrator 9.00 
3   Adm 1   4.00 
4   Adm 2   2.00 
5   Adm 1_1  1.00 

注意:ここで私は上記の例に基づいてほしい出力ですTotalHours列の1.00になり、目的の表の4.00になりました。 ID 1と2のOrgIdがTotalHoursで9.00の値を得たときも同じことが起こります。

ご協力いただければ幸いです。

2016年9月5日で編集

、12.02は、テーブルやクエリの私の試みの関係を追加しました。

ここでは、関係の外観はTable Relationshipです。あなたはNestetについて考えることは摂餌を設定します

With OrgTree (OrgId, OrgName, TotalHours) AS 
(
SELECT  orgId, orgN, SUM(eReal) AS TotalHours 
FROM  (SELECT OrgId AS orgId, OrgName AS orgN, CASE WHEN x.TotalOtReal IS NULL THEN 0 ELSE x.TotalOtReal END AS eReal 
FROM  (SELECT f.OrgId, f.OrgName, o.TotalOtReal 
FROM  dbo.CsOrganization AS f LEFT OUTER JOIN 
(SELECT  OrgId, SUM(TotalOtReal) AS TotalOtReal 
FROM  (SELECT a.EmpId, a.OrgId, b.TotalOtReal 
FROM  dbo.EmHisOrganization AS a LEFT OUTER JOIN 
(SELECT  EmpId, SUM(TotalOtReal) AS TotalOtReal 
FROM  dbo.EmOvertime AS a 
GROUP BY EmpId) AS b ON a.EmpId = b.EmpId) AS a_1 
GROUP BY OrgId) AS o ON f.OrgId = o.OrgId 
) AS x WHERE OrgId = 1) AS xx 
GROUP BY orgId, orgN 

UNION ALL 
SELECT a.OrgId, a.OrgName, TotalHours FROM dbo.CsOrganization a 
INNER JOIN OrgTree o ON a.OrgParentId = o.OrgId 
) 
SELECT a.OrgId, a.OrgName, SUM(a.TotalHours) AS TotalHours FROM OrgTree a 
GROUP BY a.OrgId, a.OrgName 
+1

関連するRDBMSのタグ、および問題を解決するのも、あなたの試みを含むようにあなたの質問を編集してください。 –

+0

私は上記の質問を編集しました。どうぞご覧ください。 – Reynaldi

+0

でも、あなたが作業しているデータベースはまだわかりません。 cteは多くのプラットフォームでサポートされています。それはSQLサーバー、オラクル、ポストグル、何か他のですか? –

答えて

2

サンプルデータ

DECLARE @CsOrganization TABLE (OrgId int, OrgParentId int, OrgName nvarchar(50)); 
INSERT INTO @CsOrganization (OrgId, OrgParentId, OrgName) VALUES 
(1, NULL, 'X COMPANY'), 
(2, 1 , 'Administrator'), 
(3, 2 , 'Adm 1'), 
(4, 2 , 'Adm 2'), 
(5, 3 , 'Adm 1_1'); 

DECLARE @EmHisOrganization TABLE (EmpId int, OrgId int); 
INSERT INTO @EmHisOrganization (EmpId, OrgId) VALUES 
(1, 2), 
(2, 2), 
(3, 3), 
(4, 4), 
(5, 5); 

DECLARE @EmOvertime TABLE (EmpId int, TotalOtReal float); 
INSERT INTO @EmOvertime (EmpId, TotalOtReal) VALUES 
(1, 1.00), 
(2, 2.00), 
(3, 3.00), 
(4, 2.00), 
(5, 1.00); 

クエリ

  • CTE_OrgHoursは、各組織の全従業員の残業時間の単純合計を計算します。
  • CTE_Recursiveは、組織の階層を横断する再帰的なCTEです。
  • 最終SELECTは、ツリーの各ノード(組織)の合計時間にトラバースされたツリーをグループ化します。

このクエリを段階的に実行し、CTE-by-CTEを実行し、中間結果を調べて、動作の仕組みをよりよく理解してください。

WITH 
CTE_OrgHours 
AS 
(
    SELECT 
     Org.OrgId 
     ,Org.OrgParentId 
     ,Org.OrgName 
     ,ISNULL(SUM(Overtime.TotalOtReal), 0) AS SumHours 
    FROM 
     @CsOrganization AS Org 
     LEFT JOIN @EmHisOrganization AS Emp ON Emp.OrgId = Org.OrgID 
     LEFT JOIN @EmOvertime AS Overtime ON Overtime.EmpId = Emp.EmpId 
    GROUP BY 
     Org.OrgId 
     ,Org.OrgParentId 
     ,Org.OrgName 
) 
,CTE_Recursive 
AS 
(
    SELECT 
     CTE_OrgHours.OrgId 
     ,CTE_OrgHours.OrgParentId 
     ,CTE_OrgHours.OrgName 
     ,CTE_OrgHours.SumHours 
     ,1 AS Lvl 
     ,CTE_OrgHours.OrgId AS StartOrgId 
     ,CTE_OrgHours.OrgName AS StartOrgName 
    FROM CTE_OrgHours 

    UNION ALL 

    SELECT 
     CTE_OrgHours.OrgId 
     ,CTE_OrgHours.OrgParentId 
     ,CTE_OrgHours.OrgName 
     ,CTE_OrgHours.SumHours 
     ,CTE_Recursive.Lvl + 1 AS Lvl 
     ,CTE_Recursive.StartOrgId 
     ,CTE_Recursive.StartOrgName 
    FROM 
     CTE_OrgHours 
     INNER JOIN CTE_Recursive ON CTE_Recursive.OrgId = CTE_OrgHours.OrgParentId 
) 
SELECT 
    StartOrgId 
    ,StartOrgName 
    ,SUM(SumHours) AS TotalHours 
FROM CTE_Recursive 
GROUP BY 
    StartOrgId 
    ,StartOrgName 
ORDER BY StartOrgId; 

結果

+------------+---------------+------------+ 
| StartOrgId | StartOrgName | TotalHours | 
+------------+---------------+------------+ 
|   1 | X COMPANY  |   9 | 
|   2 | Administrator |   9 | 
|   3 | Adm 1   |   4 | 
|   4 | Adm 2   |   2 | 
|   5 | Adm 1_1  |   1 | 
+------------+---------------+------------+ 
+0

を使用する必要があります。うわー、うまくいきました!どうもありがとうございました!これを答えにしました! – Reynaldi

+0

@Reynaldi、よろしくお願いします。それがあなたを助けてくれてうれしいです。 –

+0

しかし、EmOvertimeテーブルに「AttdDate」という別の列があり、同じIDを持つ多くの従業員を挿入できますが、日付が異なると、重複した子のデータが生成されることを意味します。これを避ける方法は? – Reynaldi

0

wikiを):

私のクエリの試みは、(これらは、それぞれの組織に0.00を得たが、where句は廃止された場合はアンカークエリは、正しい値を示しています) ?

OrgId LeftIndex RightIndex OrgName 
1  1   10   X COMPANY 
2  2   9    Administrator 
3  3   6    Adm 1 
4  7   8    Adm 2 
5  4   5    Adm 1_1 

SELECT O.OrgId, (SELECT Sum(EO.TotalHours) 
    FROM CsOrganization CO 
    INNER JOIN EmHisOrganization AS EHO ON CO.OrgId=EHO.OrgID 
    INNER JOIN EmOvertime AS EO ON EHO.EmpId=EO.EmpId 
    WHERE CO.LeftInde>=O.LeftIndex AND CO.RightIndex<=O.RightIndex) AS TotalHours 
FROM CsOrganization O 
+0

LeftIndexとRightIndexの値はどのように知っていますか? CsOrganizationテーブルに別の2つの列を追加する必要がありますか? – Reynaldi

+0

はい、あなたは、OrgParentId列の代わりに2つの列を追加します。新しい列を持たない別の方法があります。合計を計算する関数を作成する必要があります。 –

+0

サブクエリでWITH式を使用することはできませんので、関数 –

関連する問題