https://qiita.com/Shoyu_N/items/f1786f99545fa5053b75
再帰SQLは、階層的なデータを「再帰的に」取得するときなどに使うSQL構文。
WITH RECURSIVE キーワードを使って記述する。
例えばツリー状データがテーブルに入っているとき、特定のノードの子孫のみを取得する場合などに使う。
一番単純な例は以下。
WITH RECURSIVE number_sequence AS ( SELECT 1 AS num UNION ALL SELECT number_sequence.num + 1 AS num FROM number_sequence WHERE num < 5 ) SELECT * FROM number_sequence; -- 【結果】 -- num -- ----- -- 1 -- 2 -- 3 -- 4 -- 5
再帰SQLを作るときの考え方は、まず「WITH RECURSIVEで定義した仮想テーブル」に作りたい再帰データが無限に入っていることを想定して SELECT や WEHRE を抜きにしたSQLを書く。
その後、その目的とするデータを入れるためにはSELECTやWHEREがどうなっているべきかを考える。
上の例について考えてみる。
1. 「WITH RECURSIVEで定義した仮想テーブル」に作りたい再帰データが無限に入っていることを想定したSQLを書く
SELECT 1 AS num UNION ALL SELECT 《不明》 as num FROM number_sequence《この中には1,2,3,4,5,6...が入っている》 WHERE 《不明》
2. どうやったら作りたい再帰データが入るSQLになるかを考えて、SELECTを書く
SELECT 1 AS num UNION ALL SELECT (number_sequence.num + 1) AS num FROM number_sequence《この中には1,2,3,4,5,6...が入っている》 WHERE 《不明》
3. どうやったら最終的に得たい結果である「1~5」になるかを考えて、WHEREやテーブル内部結合を書く
SELECT 1 AS num UNION ALL SELECT (number_sequence.num + 1) AS num FROM number_sequence《この中には1,2,3,4,5,6...が入っている》 WHERE number_sequence.num < 5
以上で完成。
ツリー状データに対して、あるノード子孫を全て取得したい場合の例は以下のようになる。
-- 【データのイメージ】
-- a -+- a1 -+- a1-1
-- | |
-- | +- a1-2
-- +- a2
--
-- b -+- b1
-- |
-- +- b2
-- 【データ作成】
CREATE TABLE node_list (
node VARCHAR(10),
parent_node VARCHAR(10)
);
INSERT INTO node_list VALUES ('a' , null);
INSERT INTO node_list VALUES ('a1' , 'a');
INSERT INTO node_list VALUES ('a1-1', 'a1');
INSERT INTO node_list VALUES ('a1-2', 'a1');
INSERT INTO node_list VALUES ('a2' , 'a');
INSERT INTO node_list VALUES ('b' , null);
INSERT INTO node_list VALUES ('b1' , 'b');
INSERT INTO node_list VALUES ('b2' , 'b');
-- 【'a' の子孫を取得するSQL 】
WITH RECURSIVE node_childlen AS (
SELECT node, parent_node, 1 AS deep_level FROM node_list WHERE node = 'a'
UNION ALL
SELECT n.node, n.parent_node, (p.deep_level+1) AS deep_level
FROM node_list n
INNER JOIN node_childlen p ON n.parent_node = p.node
)
SELECT * FROM node_childlen;
-- 【結果】
node parent_node deep_level
------- ----------- -------------
a null 1
a1 a 2
a2 a 2
a1-1 a1 3
a1-2 a1 3