4

仕事中にクエリに出くわしましたが、それがどのように機能するのか正確に理解できませんでした。クエリが行うことは、今日その親である人のすべての親を探すことです。

ここでの秘訣は、各親子関係に有効な期間があることです。

このデータセットを参照してください。

祖父母は2012年1月1日から2015年2月2日まで父の親です

父は2012年1月1日から2011年2月2日まで子の親です

子供はただ最低レベルの人です

NewFatherは、2012年1月1日から2014年2月2日までの子の親です。

現在、子供に今日有効な親のリストは、NewFather

リストを取得するために、以前は次のSQLを使用していました。

SELECT connect_by_root per_id2 AS per_id2,
       per_id1,
       LEVEL                   AS per_level,
       n.entity_name
FROM   ci_per_per pp,
       ci_per_name N
WHERE  N.per_id = per_id1
       AND start_dt <= SYSDATE
       AND ( end_dt IS NULL
              OR end_dt >= SYSDATE )
START WITH per_id2 = :personID
CONNECT BY NOCYCLE PRIOR per_id1 = per_id2;

personIDバインドされた変数はどこですか

where句の動作は、最初にすべてのレコードを取得してから、非結合条件をチェックする(開始日と終了日をチェックする)ため、このクエリは機能しませんでした。これにより、NewFather, GrandParent完全に間違っている親のリストが表示されます。

したがって、クエリは次のように変更されました。

SELECT connect_by_root per_id2 AS per_id2,
       per_id1,
       LEVEL                   AS per_level,
       n.entity_name
FROM   ci_per_per pp,
       ci_per_name N
WHERE  N.per_id = per_id1
       AND start_dt <= SYSDATE
       AND ( end_dt IS NULL
              OR end_dt >= SYSDATE )
START WITH per_id2 = (SELECT per_id
                      FROM   ci_acct_per
                      WHERE  per_id = :personID
                             AND pp.start_dt <= SYSDATE
                             AND ( pp.end_dt IS NULL
                                    OR pp.end_dt >= SYSDATE ))
CONNECT BY NOCYCLE PRIOR per_id1 = per_id2;

今私が理解していないのは:

start with句のwhere条件は、このような方法でクエリの動作にどのように影響しますか?

このクエリについて私が嫌うもう1つの点は、という名前の完全に無関係なテーブルを使用していることです。このテーブルには、の各人ci_acct_perの列が含まれているだけです。per_idci_per_per

もっと上手くできますか?元のクエリを修正するためのよりクリーンなアプローチはありますか?

アップデート

このクエリは、階層の上位を移動する場合にのみ機能し、子を探している場合は機能しません。ただし、このクエリは子を検索することはなく、検索することも想定されていません。

4

2 に答える 2

2

私があなたを正しく理解しているかどうかはわかりませんが、なぜですか?

SELECT connect_by_root per_id2 AS per_id2,
       pp.per_id1,
       LEVEL                   AS per_level,
       n.entity_name
FROM   (select * 
        from ci_per_per
       where start_dt <= SYSDATE
       AND ( end_dt IS NULL
              OR end_dt >= SYSDATE )) pp join
       ci_per_name N on N.per_id = pp.per_id1         
START WITH per_id2 = 1
CONNECT BY NOCYCLE PRIOR pp.per_id1 = pp.per_id2;

これがsqlfiddleのデモです


@ user1395の例に感謝ます

奇妙なクエリが機能しないので、どうして機能するのかを説明するのは難しいです...

実際に発生するのは、START WITH句が「の父」列であるper_id2を使用しているため、複数ある場合(1つはsysdateに関連しない)でも、それから始める必要はありません。
言い換えれば、それは「子供」からではなく、「子供」の父親、つまり「父親」と「新しい父親」から始まります。

したがって、@ user1395の提案を使用してconnect by、父親が関連しない場合に停止するstart with句と、関連する父親のみを使用可能にする句の両方に日付ロジックを含めるか、最初に関連性のないすべての父親を削除します(私の以前の提案のように) )または「子」から「開始」し、その父親ではありません。

select * from (
SELECT connect_by_root per_id1 AS per_id2,
       per_id1,
       LEVEL                   AS per_level,
       n.entity_name
FROM   ci_per_per pp,
       ci_per_name N
WHERE  N.per_id = per_id1       
START WITH per_id1 = 1
CONNECT BY NOCYCLE PRIOR per_id1 = per_id2 AND start_dt <= SYSDATE
       AND ( end_dt IS NULL
              OR end_dt >= SYSDATE ))
where per_id1 <> per_id2;

別のsqlfiddleデモ

于 2013-02-14T11:08:26.387 に答える
1

connectby句内で日付ロジックを使用できます。

SELECT connect_by_root per_id2 AS per_id2,
       per_id1,
       LEVEL                   AS per_level,
       n.entity_name
FROM   ci_per_per pp,
       ci_per_name N
WHERE  N.per_id = per_id1
START WITH per_id2 = :personID AND 
                         SYSDATE BETWEEN start_dt AND NVL(end_dt,SYSDATE)
CONNECT BY NOCYCLE PRIOR per_id1 = per_id2 AND 
                         SYSDATE BETWEEN start_dt AND NVL(end_dt,SYSDATE);

現在の日付に有効な親がいない場合、これは上昇を停止します。

于 2013-02-14T09:11:33.613 に答える