少しだけ時間が出来たので、以前使おうか迷っていたPostgreSQLのWITH RECURSIVEを使って複数点間の移動経路と距離を求めるようなSQLを作ってみました。
※使おうと思ってた箇所は、計算Costが問題になりそうだったので、結局group化する列を追加して対応しましたが。
ある地点から別の地点へ行ける組合せを登録するテーブルを作ります。
CREATE TABLE public.pair( p1 text, -- 開始地点 p2 text, -- 到達地点 distance integer -- 距離 );
以下のデータを作り、距離はランダムに入れました。
p1 p2 distance A B 8 C K 91 D B 66 E D 78 F E 44 G F 36 H G 2 I H 23 J H 94 M K 28
今回は逆順でp2からp1へも同じ距離distanceで行く事を可としましたので、これをviewで対応します。
CREATE OR REPLACE VIEW public.pair2 AS SELECT p1, p2, distance FROM pair UNION SELECT p2 AS p1,p1 AS p2, distance FROM pair ;
このpair2に対して再帰問い合わせを使ってみます。
・今回は数が多くないので繰り返し回数無制限でも良いんですが、一応10回未満とするためn列を追加します。
・また、途中の経路が分からないのも微妙だったので、route配列を追加します。
WITH RECURSIVE r AS( SELECT p1,p2,distance ,1 as n , array[p1, p2] AS route FROM pair2 UNION SELECT r.p1, p.p2, r.distance+p.distance as distance,n+1 , route||array[p.p2] FROM pair2 p JOIN r ON p.p1 = r.p2 -- 関連key AND r.p1 != p.p2 -- 同じ値は不要 AND NOT(p.p2 = ANY(route)) -- 一度通った場所は通らない WHERE n+1 < 10 -- 継続回数を指定 ) SELECT * FROM r WHERE p1 = 'A' ORDER BY p1,p2,n,distance;
結果です。
distanceが加算されて行ってるのが分かります。
またAとC,K,Mは関連データが無いので、経路は出ていません。
p1 p2 distance n route A B 8 1 {A,B} A D 74 2 {A,B,D} A E 152 3 {A,B,D,E} A F 196 4 {A,B,D,E,F} A G 232 5 {A,B,D,E,F,G} A H 234 6 {A,B,D,E,F,G,H} A I 257 7 {A,B,D,E,F,G,H,I} A J 328 7 {A,B,D,E,F,G,H,J}