2017-02-21 5 views
-1

私は構造下記のように私のテーブル内のデータを持っている、のOracle SQL >>同じテーブル内の親、子や孫のための階層問合せ

Manager Id Employee id chartfield 
SM1   MGR-1  12 
SM2   MGR-1  12 
MGR-1   LEAD-1  12 
MGR-1   LEAD-2  12 
MGR-1   LEAD-3  12 
LEAD-1  LEAD-2  12 
LEAD-1  ASSOCIATE -1 12 
LEAD-1  ASSOCIATE -2 12 
LEAD-2  LEAD-3   12 
LEAD-2  ASSOCIATE -3 12 
LEAD-2  ASSOCIATE -4 12 
LEAD-3  ASSOCIATE -5 12 
LEAD-3  ASSOCIATE -6 12 
ASSOCIATE -1 JUNIOR - 1 12 
ASSOCIATE -1 JUNIOR - 2 12 
ASSOCIATE -2 JUNIOR - 1 12 
ASSOCIATE -2 JUNIOR - 2 12 

私は、彼らが存在しているレベルの管理者と従業員との出力を期待しています。ここでの唯一の基準は、同じ従業員が複数のマネージャーに報告できるということです。この場合、最低レベルの従業員に報告している明確な従業員だけを選択する必要があります。上記のケースでは、LEAD-2はMGR-1とLEAD-1に報告していますが、最低レベルを検討しています。

サンプル出力は、構造下記のようなことができ、

Manager Id Employee id chartfield LEVEL1 
MGR-1 LEAD-1   12   1 
MGR-1 LEAD-2   12   1 
MGR-1 LEAD-3   12   1 
MGR-1 ASSOCIATE -1 12   2 
MGR-1 ASSOCIATE -2 12   2 
MGR-1 ASSOCIATE -3 12   2 
MGR-1 ASSOCIATE -4 12   2 
MGR-1 ASSOCIATE -5 12   2 
MGR-1 ASSOCIATE -6 12   2 
MGR-1 JUNIOR - 1  12   3 
MGR-1 JUNIOR - 2  12   3 
+0

Plsは関連する製品タグのみを使用します – Shadow

+0

http://stackoverflow.com/questions/tagged/oracle+recursive-queryまたはhttp://stackoverflow.com/questions/tagged/oracle+connect-by –

+0

MGR- 1 SM1とSM2への報告(どちらも同じレベルにあるようです)?両方のレコードを出力に保持するのか、それとも1つだけ保持するのか? – miazo

答えて

0

あなたのサンプルデータが重複した管理者は一つだけである必要があり、すなわち適切に処理しなければならないと仮定して、とにかく...誰もがSM1とSM2に報告されていることを示して選択し、どのように次のクエリについて:

WITH t (
    MANAGER_ID, 
    EMPLOYEE_ID, 
    LEVEL_NUM 
) AS (
    SELECT 
    e.MANAGER_ID, 
    e.MANAGER_ID, 
    0 AS LEVEL_NUM 
    FROM 
    emp e 
    WHERE 
    e.MANAGER_ID NOT IN (
     SELECT 
     e.EMPLOYEE_ID 
     FROM 
     emp e 
    ) 
    UNION ALL 
    SELECT 
     t.MANAGER_ID, 
     e.EMPLOYEE_ID, 
     t.LEVEL_NUM + 1 AS LEVEL_NUM  
    FROM 
     emp e 
    JOIN 
     t 
    ON 
     e.MANAGER_ID = t.EMPLOYEE_ID 
) 
SELECT 
    MANAGER_ID, 
    EMPLOYEE_ID, 
    LEVEL_NUM 
FROM 
    (
    SELECT 
     MANAGER_ID, 
     EMPLOYEE_ID, 
     LEVEL_NUM, 
     ROW_NUMBER() OVER (PARTITION BY EMPLOYEE_ID ORDER BY LEVEL_NUM, MANAGER_ID) AS ROW_NUM 
    FROM 
     t 
) t 
WHERE 
    t.ROW_NUM = 1 -- keep only the first manager 
AND 
    t.LEVEL_NUM > 0 -- exclude top level managers reporting to themselves 
ORDER BY 
    t.LEVEL_NUM, 
    t.MANAGER_ID, 
    t.EMPLOYEE_ID; 

とデータにサイクルに対処するためのクエリ:

WITH t (
    MANAGER_ID, 
    EMPLOYEE_ID, 
    PATH, 
    LEVEL_NUM 
) AS (
    SELECT 
    e.MANAGER_ID, 
    e.MANAGER_ID, 
    '> ' || e.MANAGER_ID AS PATH, 
    0 AS LEVEL_NUM 
    FROM 
    emp e 
    UNION ALL 
    SELECT 
     t.MANAGER_ID, 
     e.EMPLOYEE_ID, 
     t.PATH || ' > ' || e.EMPLOYEE_ID AS PATH, 
     t.LEVEL_NUM + 1 AS LEVEL_NUM 
    FROM 
     emp e 
    JOIN 
     t 
    ON 
     e.MANAGER_ID = t.EMPLOYEE_ID 
    WHERE 
    t.PATH NOT LIKE '%> ' || e.EMPLOYEE_ID || '%' 
) 
SELECT 
    t.MANAGER_ID, 
    t.EMPLOYEE_ID, 
    t.LEVEL_NUM 
FROM 
    (
    SELECT 
     t.MANAGER_ID, 
     t.EMPLOYEE_ID, 
     t.LEVEL_NUM, 
     ROW_NUMBER() OVER (PARTITION BY t.MANAGER_ID, t.EMPLOYEE_ID ORDER BY t.LEVEL_NUM) AS ROW_NUM 
    FROM 
     t 
) t 
WHERE 
    t.ROW_NUM = 1 -- keep only the first employee occurance 
AND 
    t.LEVEL_NUM > 0 -- exclude top level managers reporting to themselves 
AND 
    t.MANAGER_ID = 'SM1' -- selected manager 
ORDER BY 
    t.LEVEL_NUM, 
    t.MANAGER_ID, 
    t.EMPLOYEE_ID; 
+0

実行時には、マンガーIDを 'MGR-1'として、すべてのリード、アソシエート、ジュニアレポートを彼に渡します。しかし、上記のSQLはサイクルの冗長性エラーを与えています。 – googly

+0

サイクルエラーが発生した場合は、テストデータを循環させます(ここに掲載されたサンプルデータではなく、最初のクエリが正常に実行されます)。私はそれに対処するために他のクエリを追加しました。これがあなたの問題を解決するかどうか確認してください。 – miazo