[pgsql-jp: 28158] 階層問い合わせ関数 (PL/pgSQLで行を返すサンプル 7.3にて)
Mashiki
mashiki @ yanah.com
2002年 12月 3日 (火) 05:50:05 JST
Mashikiです。
oracleで言うところのstart with、connect by句を用いた階層問合わせの
ようなものをplpgsqlで実現してみるサンプルを作ってみました。
# 私は過去この方法を聞くために当MLへの入会しましたので万感の思いです。
/* テーブル定義 (pidは親のidです) */
create table treetest (
id int4,
name text,
pid int4,
primary key(id)
);
/* サンプルデータ */
insert into treetest values (1, 'aaa', null);
insert into treetest values (2, 'abb', 1);
insert into treetest values (3, 'acc', 1);
insert into treetest values (4, 'bdd', 2);
insert into treetest values (5, 'cee', 3);
insert into treetest values (6, 'cff', 3);
/* tree 階層問い合わせ関数サンプル */
create or replace function tree(int4) returns setof record as '
declare
rec1 record;
rec0 record;
cnt int4;
begin
cnt := 0;
select $1, 0, cnt into rec0;
return next rec0;
for rec1 in
select *
from tree0($1, 1) as t(id int4, level int4)
loop
cnt := cnt+1;
select rec1.id, rec1.level, cnt into rec0;
return next rec0;
end loop;
return;
end;
' language 'plpgsql';
/* tree 再帰部分 */
create or replace function tree0(int4, int4) returns setof record as '
declare
rec1 record;
rec2 record;
begin
for rec1 in
select id, $2
from treetest
where pid = $1
order by id
loop
return next rec1;
for rec2 in
select *
from tree0(rec1.id, $2+1) as t(id int4, level int4)
loop
return next rec2;
end loop;
end loop;
return;
end;
' language 'plpgsql';
/* 呼び出しサンプル */
select id, pid, name, tree.level, lpad('',tree.level)||name
from treeTest
join tree(1) as tree(id int4, level int4, ord int4) using(id)
order by tree.ord
;
結果
id | pid | name | level | ?column?
----+-----+------+-------+----------
1 | | aaa | 0 | aaa
2 | 1 | abb | 1 | abb
4 | 2 | bdd | 2 | bdd
3 | 1 | acc | 1 | acc
5 | 3 | cee | 2 | cee
6 | 3 | cff | 2 | cff
(6 rows)
と、一応期待通りの動作を得られました。
まだ、この方法だと
・テーブル毎に関数を定義しなくてはならない
・idと親idの列名も固定されている
・idの型も決めうちになっている
・親が同じ場合、兄弟に相当する行の並び順がid順固定になる
(これはoracleでもコントロールできたか不明)
・再帰部をスマートに書きたい(2番目のselectを書きたくない)
など、クリアしたい部分もあるのでもう少し掘ってみます。
pgsql-jp メーリングリストの案内