2017-04-26 6 views
-1

コンテキストPostgresクエリで複数の1対多のリレーションシップを管理する

私はビークルルーティング問題のバリエーションを実行するアプリケーションを作成しています。このアプリケーションにはルートのルート、停車駅、運転ルートがあります。私はルートのすべての関連する属性を組み合わせたビューのクエリを書く必要があります。したがって、単一のクエリで多数の多対多の関係にroutesテーブルを結合する必要があります。

クエリの詳細

ルートテーブル、route_stop_joinテーブルと経路方向テーブルがあります。ルートとストップの関係は本当に多くのものか​​ら多くのものですが、ストップIDのリストだけが必要なので、ジョイン・テーブルとの1対多の関係を考えてください。次のクエリでは、nは停止回数である合計nは時間をカウント:

select  r.id, 
      array_agg(j.stop_id) as stops, 
      sum(rd.time_elapsed) as total_time, 
      sum(rd.drive_distance) as total_distance 
from  routes_directions rd 
right join routes r 
on   rd.route_id = r.id 
left join routes_stops_join j 
on   r.id = j.route_id 
group by r.id; 

私はこのような副選択を使用してこれを行うことができます。

select rj.id, 
     rj.stops, 
     sum(rd.time_elapsed) as total_time, 
     sum(rd.drive_distance) as total_distance 
from routes_directions rd 
right join (select r.id, 
        array_agg(j.stop_id) as stops 
      from routes r 
      left join routes_stops_join j 
      on r.id = j.route_id 
      group by r.id) rj 
on  rj.id = rd.route_id 
group by rj.id, rj.stops; 

が、私があるかどうかを確認したいと思いますsubselectsなしで単一のクエリでこれを行う方法。

+1

左はSQLを正当化!?!あなたは本当にそのように書いていますか、それともコピー&ペーストの問題ですか - そして、とにかくそれを読むことを期待しています。 – jarlh

+0

@McNets、あなたの編集の前に私のコメントを書いた。今はもっと良く見えます! – jarlh

+0

私は編集後にあなたのコメントを見ました。それは時間旅行の問題です。 @jarlh – McNets

答えて

1

限り、このクエリは、必要な情報の99%を返すよう:

select  rd.id, 
      sum(rd.time_elapsed) as total_time, 
      sum(rd.drive_distance) as total_distance 
from  routes_directions rd 
group by rd.id; 

私は、サブクエリまたはCTEを使用することをお勧めしますが、LEFTを使用すると、JOINの代わりに、RIGHT JOINのだろう。

create table routes(id int); 
insert into routes values (1),(2); 
create table routes_stops(route_id int, stop_id int); 
insert into routes_stops values (1,1),(1,2),(2,1),(2,3),(2,4); 
create table routes_directions(route_id int, dir_id int, time_elapsed int, drive_distance int); 
insert into routes_directions values (1,1,100,40),(1,2,60,60),(2,1,15,14),(2,3,20,30); 
select rj.id, 
     rj.stops, 
     sum(rd.time_elapsed) as total_time, 
     sum(rd.drive_distance) as total_distance 
from routes_directions rd 
left join (select r.id, 
        array_agg(j.stop_id) as stops 
      from  routes r 
      left  join routes_stops j 
      on  r.id = j.route_id 
      group by r.id) rj 
on  rj.id = rd.route_id 
group by rj.id, rj.stops; 
 
id | stops | total_time | total_distance 
-: | :------ | ---------: | -------------: 
2 | {1,3,4} |   35 |    44 
1 | {1,2} |  160 |   100 
with stp as 
(
    select r.id, 
      array_agg(j.stop_id) as stops 
    from routes r 
    left join routes_stops j 
    on  r.id = j.route_id 
    group by r.id 
) 
select  rd.route_id, 
      stp.stops, 
      sum(rd.time_elapsed) as total_time, 
      sum(rd.drive_distance) as total_distance 
from  routes_directions rd 
left join stp 
on   stp.id = rd.route_id 
group by rd.route_id, stp.stops; 
 
route_id | stops | total_time | total_distance 
-------: | :------ | ---------: | -------------: 
     1 | {1,2} |  160 |   100 
     2 | {1,3,4} |   35 |    44 

dbfiddle here

+0

これは副選択よりもきれいですが、それは全く機能的に違いますか?それは確かにきれいです! –

+0

この質問では、基本的に同じです、あなたは実行計画を見て確認することができます。 – McNets

+0

CTEは少し良くなったようですが、明らかに十分なデータがありません。 http://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=d13cd15c9e06f754e5c0cacf1d709a2d – McNets

関連する問題