2017-04-26 158 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