[pgsql-jp: 40411] Re: 階層問い合わせの使い方について
Tomoaki Sato
sato @ sraoss.co.jp
2010年 9月 21日 (火) 16:12:41 JST
佐藤です。
> 佐藤です。
>
> 8.3 で再帰問い合わせが使えないから connectby 関数でやっているんですね。
> もうちょっと考えてみます。
スマートではないですが、自己結合すればできますね。
=# SELECT DISTINCT g.key, g.key_p, g.name
-# FROM goods AS g, goods AS g2
-# WHERE g.key IN (
(# SELECT g3.key
(# FROM connectby('goods', 'key', 'key_p', g2.key, 0)
(# AS t(key text, key_p text, level int), goods AS g3
(# WHERE g3.key = t.key
(# ) AND g2.name LIKE '%菓子%';
key | key_p | name
------+-------+------------
1500 | 1000 | お菓子
1510 | 1500 | 和菓子
1511 | 1510 | 生和菓子
1512 | 1510 | まんじゅう
1513 | 1510 | ようかん
1514 | 1510 | せんべい
1515 | 1510 | 最中
1520 | 1500 | 洋菓子
1521 | 1520 | プリン
1522 | 1520 | ゼリー
1523 | 1520 | ケーキ
1524 | 1520 | パイ
1525 | 1520 | カステラ
(13 rows)
ただ、これなら 1 つの SQL にこだわらず、条件に一致するキーを取得し、キー
ごとに connectby 関数を実行したほうがいいかもしれません。
>> 佐藤です。
>>
>>> お世話になります、大熊と申します。
>>>
>>> 環境:PostgreSQL 8.3.7
>>>
>>> create table goods (key char(4), key_p char(4), name text);
>>>
>>> insert into goods (key, key_p, name) values ('1000', '0000', '食べ物');
>>> insert into goods (key, key_p, name) values ('2000', '0000', '飲み物');
>>> insert into goods (key, key_p, name) values ('3000', '0000', 'ファッション');
>>> insert into goods (key, key_p, name) values ('4000', '0000', 'インテリア');
>>> insert into goods (key, key_p, name) values ('1100', '1000', '肉');
>>> insert into goods (key, key_p, name) values ('1200', '1000', '魚');
>>> insert into goods (key, key_p, name) values ('1300', '1000', '野菜');
>>> insert into goods (key, key_p, name) values ('1400', '1000', 'くだもの');
>>> insert into goods (key, key_p, name) values ('1500', '1000', 'お菓子');
>>> insert into goods (key, key_p, name) values ('1600', '1000', 'パン');
>>
>> ここから
>>
>>> insert into goods (key, key_p, name) values ('1510', '1500', '和菓子');
>>> insert into goods (key, key_p, name) values ('1520', '1500', '洋菓子');
>>> insert into goods (key, key_p, name) values ('1510', '1511', '生和菓子');
>>> insert into goods (key, key_p, name) values ('1510', '1512', 'まんじゅう');
>>> insert into goods (key, key_p, name) values ('1510', '1513', 'ようかん');
>>> insert into goods (key, key_p, name) values ('1510', '1514', 'せんべい');
>>> insert into goods (key, key_p, name) values ('1510', '1515', '最中');
>>> insert into goods (key, key_p, name) values ('1520', '1521', 'プリン');
>>> insert into goods (key, key_p, name) values ('1520', '1522', 'ゼリー');
>>> insert into goods (key, key_p, name) values ('1520', '1523', 'ケーキ');
>>> insert into goods (key, key_p, name) values ('1520', '1524', 'パイ');
>>> insert into goods (key, key_p, name) values ('1520', '1525', 'カステラ');
>>
>> ここまでの key と key_p 列の値は逆でないでしょうか。
>>
>>> このようなデータを階層問い合わせを用いて「お菓子」以下をコードを指定
>>> して取得する場合は以下のように行いますが、
>>>
>>> select goods.*
>>> from connectby ( 'goods', 'key', 'key_p', '1500', 0)
>>> as tree (key text, key_p text, level int ), goods
>>> where goods.key = tree.key;
>>>
>>> コード指定ではなく、引き渡される情報が"菓子"で項目nameに対してlike検
>>> 索をかけて取得する場合はどのように行ったらよいのでしょうか?
>>> ( 'goods', 'key', 'key_p', '1500', 0)
>>
>> connectby 関数はほとんど使ったことがないので connectby 関数でどう書く
>> かはすぐには分かりませんが、8.4 以降であれば再帰問い合わせを使って以下
>> のように書けると思います。
>>
>> =# WITH RECURSIVE t (key, key_p, name) AS (
>> (# SELECT g.key, g.key_p, g.name
>> (# FROM goods AS g WHERE g.name LIKE '%菓子%'
>> (# UNION SELECT g.key, g.key_p, g.name
>> (# FROM goods AS g, t WHERE g.key_p = t.key
>> (# ) SELECT t.key, t.key_p, t.name FROM t;
>> key | key_p | name
>> ------+-------+------------
>> 1500 | 1000 | お菓子
>> 1510 | 1500 | 和菓子
>> 1520 | 1500 | 洋菓子
>> 1511 | 1510 | 生和菓子
>> 1512 | 1510 | まんじゅう
>> 1513 | 1510 | ようかん
>> 1514 | 1510 | せんべい
>> 1515 | 1510 | 最中
>> 1521 | 1520 | プリン
>> 1522 | 1520 | ゼリー
>> 1523 | 1520 | ケーキ
>> 1524 | 1520 | パイ
>> 1525 | 1520 | カステラ
>> (13 rows)
>>
>>> この部分を動的に変えたいのですが、SQL一発では無理なのでしょうか?
----
佐藤 友章 <sato @ sraoss.co.jp>
SRA OSS, Inc. 日本支社
PostgreSQL トレーニング: http://www.sraoss.co.jp/prod_serv/training/
PowerGres ファミリー: http://powergres.sraoss.co.jp/
pgsql-jp メーリングリストの案内