2017-04-26 155 views
-1

上下文Postgres在查詢中管理多個一對多關係

我正在寫一個應用程序,對車輛路徑問題進行變更。該應用程序具有路線,停靠點和路線行駛方向。我需要爲一個視圖編寫查詢,該視圖組合了路由的所有相關屬性。因此,我需要將路由表連接到單個查詢中的多對多關係。

查詢詳細

有路由表,該表route_stop_join和路由表的方向。路線和站點之間的關係實際上是多對多的,但我們只需要一個stop id列表,因此可以考慮與連接表的一對多關係。下面的查詢計算總和n次,其中n是停止的次數:

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; 

,但我想看看是否有一個:

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; 

我可以在此使用子查詢這樣做在沒有子選擇的單個查詢中執行此操作的方法。

+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