6

この投稿のとおり、答えは「WITH RECURSIVE」を使用するように思われることはわかっていますが、うまくいきません。

と呼ばれるpeopleテーブルと。と呼ばれるテーブルがありますposition_hierarchypeopleテーブルには、私たちが呼び出す一意のIDとuperson_id位置ID、pcnおよびenabledフラグがあります(誰かが離れて置き換えられた場合、それらの置き換えは同じになるためpcn)。にはposition_hierarchy列があり、階層内でその上の人の列であるpcn別の列があります。私がやりたいのは、ある人を与えて、階層内でその上の人のすべてを見つけること、および/または他の人を与えて、2番目の人が最初の人よりも監督的な立場にあるかどうかを伝えることです。reports_topcnuperson_iduperson_iduperson_iduperson_id

pcn彼らは彼らと同じであるため、会社の社長が示されていreports_toます。(私の決定ではありません-私はnullを使用したでしょうreports_to

私がこれまでに思いついたのは:

with recursive parents (uperson_id, pcn, reports_to) as
(
 select p1.uperson_id, ph1.pcn, ph1.reports_to
 from people p1
 join position_hierarchy ph1 on ph1.pcn = p1.pcn
 where reports_to != ph1.pcn and active_revoke_flag = '0'

 union all

 select p2.uperson_id, ph2.pcn, ph2.reports_to
 from people p2
 join position_hierarchy ph2 on p2.pcn = ph2.pcn
 join parents pp on pp.pcn = ph2.reports_to
)
select parents.* from parents where uperson_id = 'aaa3644';

しかし、それは同じuperson_id、pcn、reports_toで5行を返します(これは正しい行数のようですが、各レベルでスーパーバイザーのuperson_idが必要です。非常に基本的なものが欠けているように感じます。おそらく平手打ちします。あなたが私が間違っていることを教えてくれたときの私の頭。

私がしたこと

Erwin Brandstetterの回答に基づいて、いくつかの問題を修正し(主に、どのテーブルにあるかを明確にしなかったためactive_revoke_flag)、次のことを考え出しました。

with recursive p as (
    select pcn, reports_to
    from   position_hierarchy
    where  pcn = (SELECT pcn FROM people WHERE uperson_id = 'aaa3644')
    union all
    select ph2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to AND
           p.pcn != p.reports_to
)
select p2.uperson_id, p2.active_revoke_flag, p.*
from   p
join   people p2 USING (pcn)
where  p2.active_revoke_flag = '0';
4

2 に答える 2

4

私はこのボトムアップアプローチを試し、興味のある人から始めて、上に向かって進んでいきます。

with recursive p as (
    select p1.uperson_id, p1.pcn, ph1.reports_to
    from   people p1
    join   position_hierarchy ph1 USING (pcn)
    where  ph1.active_revoke_flag = '0'
    and    p1.uperson_id = 'aaa3644'

    union all

    select p2.uperson_id, p2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to
                                 AND ph2.active_revoke_flag = '0'
    join   people p2 ON p2.pcn = ph2.pcn
)
select * from p;

personまたは、一度しか参加しないため、より高速です。

with recursive p as (
    select pcn, reports_to
    from   position_hierarchy
    where  active_revoke_flag = '0'
    and    pcn = (SELECT pcn FROM person WHERE uperson_id = 'aaa3644')

    union all

    select ph2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to
                                 AND ph2.active_revoke_flag = '0'
)
select p2.uperson_id, p.*
from   p
join   people p2 USING (pcn); -- assuming pcn is unique in table person

余談ですが、私はあなたのデザインが重複していることがpcnやや疑わしいと思います。

于 2012-09-01T21:15:12.103 に答える
-2

ツリーの最大深度がわかっている場合は、それを 1 つのクエリにまとめることができます。それ以外の場合は、Joe Chelko を読み、テーブルを再構築する必要があります。

最大深さ 5 の単一のクエリは、次のようになります (テストされていません)。

個別の ph1.pcn を選択
position_hierarchy ph1 から
ph1.pcn = ph2.reports_to で position_hierarchy ph2 に参加
ph2.pcn = ph3.reports_to で position_hierarchy ph3 に左結合
p3.pcn = ph4.reports_to で position_hierarchy ph4 に左結合
ph4.pcn = ph5.reports_to で position_hierarchy ph5 に左結合
ここで、ph2.pcn = @my_pcn
または ph3.pcn = @my_pcn
または ph4.pcn = @my_pcn
または ph5.pcn = @my_pcn;

結果は、@my_pcn のすべての上司の pcn のリストになります。また、会社の社長のエッジ ケースをテストするために何かを追加することもできます。

Chelkoは、文字通り SQL の階層に関する本を書きました。

于 2012-09-01T21:27:59.380 に答える