web-dev-qa-db-ja.com

Oracleでの単純な再帰クエリ

現在、再帰クエリの理解と記述に問題があります。情報の階層を検索するために再帰クエリが使用されることを理解していますが、階層を上に移動できる簡単なソリューションをオンラインで見つけていません。たとえば、家系図をモデル化する関係があるとします。

create table family_tree (
child varchar(10)
parent varchar(10)
);

この家系図を遡って、Originまですべての親を収集する再帰クエリを作成したい場合、どうすればよいですか?

前もって感謝します。

5
ac_nook

connect by句を使用できます。

あなたの場合、SQLは次のようになります。

select child, parent, level
from family_tree 
connect by prior parent = child
2
mkuligowski

私があまり馴染みのないANSI構文があり、通常使用するOracle構文があります。 Oracleの構文では、CONNECT BY ... PRIOR句を使用してツリーを構築し、START WITH句を使用して、ツリーのウォークを開始する場所をデータベースに指示します。次のようになります。

SELECT child, parent, level
  FROM family_tree
CONNECT BY ...
START WITH ...

START WITH句の方が簡単です。あなたは木を「上に」見ているので、あなたは木を歩き始めたい子供を選ぶでしょう。したがって、これはSTART WITH parent = 'John'のようになります。これがレベル1の行です。ジョンの列はツリーの最下部なので、ジョンの行には親があり、子供はいないと想定しています。

ここで、ツリー内の行が相互にどのように関係しているかを考えます。レベル2の行を見ている場合、それが「John」行の正しい行であるかどうかをどのようにして知るのでしょうか。この場合、子列にJohnが含まれます。したがって、CONNECT BY PRIOR parent = childの句が必要です。つまり、「前の行の親はこの行の子と等しい」

したがって、クエリは次のようになります。

SELECT child, parent, level
  FROM family_tree
CONNECT BY PRIOR parent = child
START WITH parent = 'John'

SQL Fiddle例

(実際の子供には2人の親がいるので、これは少し奇妙な例ですが、これはより複雑になります。)

1
eaolson

この家系図を遡って、Originまですべての親を収集する再帰クエリを作成したい場合、どうすればよいですか?

階層クエリとSYS_CONNECT_BY_PATH( column_name, delimiter )関数を使用します。

Oracle 18セットアップ

create table family_tree (
  child varchar(10),
  parent varchar(10)
);

INSERT INTO family_tree ( child, parent )
  SELECT 'B', 'A' FROM DUAL UNION ALL
  SELECT 'C', 'B' FROM DUAL UNION ALL
  SELECT 'D', 'C' FROM DUAL UNION ALL
  SELECT 'E', 'D' FROM DUAL UNION ALL
  SELECT 'F', 'C' FROM DUAL;

クエリ1

SELECT SYS_CONNECT_BY_PATH( parent, ' -> ' ) || ' -> ' || child AS path
FROM   family_tree
START WITH parent = 'A'
CONNECT BY PRIOR child = parent;

結果

PATH
-------------------------
 -> A -> B
 -> A -> B -> C
 -> A -> B -> C -> D
 -> A -> B -> C -> D -> E
 -> A -> B -> C -> F
1
MT0

SCOTT.EMP テーブル?これは「標準」のSCOTTスキーマに含まれています(残念ながら、バージョン12.1以降では、Oracleデータベースのすべてのコピーにパッケージ化されていません)。データベースを確認してください。そこにあるかもしれません。または、DBAに問い合わせてください。

とにかく、テーブルには中小企業の14人の従業員が表示され、従業員のIDと上司の従業員IDが含まれています。それでは、特定の従業員から始めて、その最高レベルのボスを見つけたいとします。 (テストの問題に似ています。)この特定の階層では、最上位の「祖先」は一意ですが、それは無関係です。各部門に「部門長」がいて、部門長の上にCEOがいない場合、再帰クエリは同じように機能します。

この配置では、「すべてのボスのボス」を識別するのは簡単です-彼にはボスがいません。彼の行では、マネージャーIDはnullです。これは、ツリーのような階層の「ルート」(または「ルート」)の非常に一般的な配置です。

これは、特定の従業員IDから始めて、再帰クエリを使用して上司を見つける方法です。これは、練習しようとしているものだと私が理解していることです。 (つまり、私が正しく理解していれば、「なんらかの方法で」問題を解決することに興味はありません。むしろ、小さな例で、再帰クエリがどのように機能するかを確認して、続くすべてを理解できるようにする必要があります。)

with
  r ( empno, mgr ) as (
    select  empno, mgr      -- ANCHOR leg of recursive query
      from  scott.emp
      where empno = 7499
    union all
    select  e.empno, e.mgr  -- RECURSIVE leg of recursive query
      from  scott.emp e inner join r on e.empno = r.mgr
  )
select empno
from   r
where  mgr is null
;

この例を理解するのが難しいかもしれない場所を推測しようとはしません。代わりに、私はあなたが尋ねるのを待ちます。

0
mathguy