0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Oracle Databaseでは再帰SQLとともにSEARCH句とCYCLE句を利用することができる

Posted at

はじめに

Oracle Databaseでは、再帰SQLとともにSEARCH句とCYCLE句を利用することができます。この記事では、SEARCH句とCYCLE句の使用例を簡単にまとめています。

サンプルスキーマ

部品マスタテーブルでは、部品名とその親の部品の部品名を管理しています。AAAを根とするツリーのように、通常ある部品は親部品を1つしか持ちませんが、部品WWWについては2つの親が誤って登録されています。そのため、PPPを根とするツリーには閉路が発生しています。

この記事では再帰SQLを利用して、根AAAや根PPPから子部品すべてと、その部品のパスを取得します。

名称未設定ファイル.drawio (2).png

CREATE TABLE 部品マスタ (部品名 CHAR(3) NOT NULL, 親部品名 CHAR(3));

INSERT INTO 部品マスタ VALUES ('AAA', NULL);
INSERT INTO 部品マスタ VALUES ('BBB', 'AAA');
INSERT INTO 部品マスタ VALUES ('CCC', 'AAA');
INSERT INTO 部品マスタ VALUES ('DDD', 'BBB');
INSERT INTO 部品マスタ VALUES ('EEE', 'CCC');
INSERT INTO 部品マスタ VALUES ('FFF', 'CCC');
INSERT INTO 部品マスタ VALUES ('GGG', 'FFF');
INSERT INTO 部品マスタ VALUES ('HHH', 'FFF');
INSERT INTO 部品マスタ VALUES ('PPP', NULL);
INSERT INTO 部品マスタ VALUES ('QQQ', 'PPP');
INSERT INTO 部品マスタ VALUES ('RRR', 'PPP');
INSERT INTO 部品マスタ VALUES ('SSS', 'QQQ');
INSERT INTO 部品マスタ VALUES ('TTT', 'RRR');
INSERT INTO 部品マスタ VALUES ('UUU', 'RRR');
INSERT INTO 部品マスタ VALUES ('VVV', 'UUU');
INSERT INTO 部品マスタ VALUES ('WWW', 'UUU');
INSERT INTO 部品マスタ VALUES ('RRR', 'WWW');

SEARCH句

SEARCH句を利用すると、深さ優先検索(DEPTH FIRST SEARCH; DFS) または 幅優先検索(BREADTH FIRST SEARCH; BFS) による順序を指定することができます。

深さ優先探索

WITH R (部品名, パス) AS (
    SELECT 部品名, 部品名 FROM 部品マスタ WHERE 部品名= 'AAA'
  UNION ALL 
    SELECT B.部品名, R.パス || ' --> ' || B.部品名
    FROM R
    JOIN 部品マスタ B ON R.部品名 = B.親部品名
)
SEARCH DEPTH FIRST BY 部品名 SET 探索順
SELECT 探索順, 部品名, パス FROM R;
探索順 部品名 パス
1 AAA AAA
2 BBB AAA --> BBB
3 DDD AAA --> BBB --> DDD
4 CCC AAA --> CCC
5 EEE AAA --> CCC --> EEE
6 FFF AAA --> CCC --> FFF
7 GGG AAA --> CCC --> FFF --> GGG
8 HHH AAA --> CCC --> FFF --> HHH

幅優先探索

WITH R (部品名, パス) AS (
    SELECT 部品名, 部品名 FROM 部品マスタ WHERE 部品名= 'AAA'
  UNION ALL 
    SELECT B.部品名, R.パス || ' --> ' || B.部品名
    FROM R
    JOIN 部品マスタ B ON R.部品名 = B.親部品名
)
SEARCH BREADTH FIRST BY 部品名 SET 探索順
SELECT 探索順, 部品名, パス FROM R;
探索順 部品名 パス
1 AAA AAA
2 BBB AAA --> BBB
3 CCC AAA --> CCC
4 DDD AAA --> BBB --> DDD
5 EEE AAA --> CCC --> EEE
6 FFF AAA --> CCC --> FFF
7 GGG AAA --> CCC --> FFF --> GGG
8 HHH AAA --> CCC --> FFF --> HHH

CYCLE句

Oracle DataBaseでは、再帰SQL実行時に閉路を検出した場合、「ORA-32044: 再帰的WITH問合せの実行中にサイクルが検出されました」エラーが発生します。

このエラーを抑制し、閉路をマークしたい場合はCYCLE句を利用します。

WITH R (部品名, パス) AS (
    SELECT 部品名, 部品名 FROM 部品マスタ WHERE 部品名= 'PPP'
  UNION ALL 
    SELECT B.部品名, R.パス || ' --> ' || B.部品名
    FROM R
    JOIN 部品マスタ B ON R.部品名 = B.親部品名
)
CYCLE 部品名 SET 閉路 to 'Y' default 'N'
SELECT 閉路, 部品名, パス FROM R;
閉路 部品名 パス
N PPP PPP
N QQQ PPP --> QQQ
N RRR PPP --> RRR
N SSS PPP --> QQQ --> SSS
N TTT PPP --> RRR --> TTT
N UUU PPP --> RRR --> UUU
N VVV PPP --> RRR --> UUU --> VVV
N WWW PPP --> RRR --> UUU --> WWW
Y RRR PPP --> RRR --> UUU --> WWW --> RRR

もちろん、SEARCH句との併用も可能です。

WITH R (部品名, パス) AS (
    SELECT 部品名, 部品名 FROM 部品マスタ WHERE 部品名= 'PPP'
  UNION ALL 
    SELECT B.部品名, R.パス || ' --> ' || B.部品名
    FROM R
    JOIN 部品マスタ B ON R.部品名 = B.親部品名
)
SEARCH DEPTH FIRST BY 部品名 SET 探索順
CYCLE 部品名 SET 閉路 to 'Y' default 'N'
SELECT 探索順, 閉路, 部品名, パス FROM R;
探索順 閉路 部品名 パス
1 N PPP PPP
2 N QQQ PPP --> QQQ
3 N SSS PPP --> QQQ --> SSS
4 N RRR PPP --> RRR
5 N TTT PPP --> RRR --> TTT
6 N UUU PPP --> RRR --> UUU
7 N VVV PPP --> RRR --> UUU --> VVV
8 N WWW PPP --> RRR --> UUU --> WWW
9 Y RRR PPP --> RRR --> UUU --> WWW --> RRR

参考

環境情報

SELECT * FROM v$version;
BANNER BANNER_FULL BANNER_LEGACY CON_ID
Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production 0
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?