SQL查询 - 根据时间表获取到达和离开站点

时间:2015-04-17 20:22:10

标签: sql oracle

我有以下表格:

  • ROUTE(id,train_number,station_id,arrival_time,departure_time)
  • SERVICE(train_number,train_name)
  • STATION(id,name,city)

ROUTE表中的一行将包含列车编号,它的到达和离开时间(如果该站是第一个/最后一个,则为这两个中的一个)和station_id。

我想找出每个train_number,它走哪条路径。我的困难在于确定每条路线的到达和离开站名称。

例如,列车1337可能具有以下路径:

  • stationA - > stationB:
    • 路线(1,1137,stationA,null,1800)
    • 路线(2,1337,stationB,1900,2000)
  • stationB - > stationC:
    • 路线(3,1337,stationC,2020,2100)
  • stationC - > stationD:
    • 路线(4,1337,stationD,2120,2200)

我想弄清楚这些路径,即stationA - > stationB - > stationC等。

如何实现(如果重要的话,我正在使用Oracle SQL)?

对于stationA(获取路线的开始)我可以执行以下操作:

SELECT name FROM STATION
WHERE station.id = ROUTE.station_id AND ROUTE.arrival IS NULL

3 个答案:

答案 0 :(得分:4)

设定:

CREATE TABLE STATION (
  id      NUMBER PRIMARY KEY,
  name    VARCHAR2(20),
  city    VARCHAR2(20)
);

CREATE TABLE SERVICE (
  train_number  NUMBER PRIMARY KEY,
  train_name    VARCHAR2(20)
);

CREATE TABLE ROUTE (
  id              NUMBER PRIMARY KEY,
  train_number    NUMBER REFERENCES SERVICE( train_number ),
  station_id      NUMBER REFERENCES STATION( id ),
  arrival_time    NUMBER,
  departure_time  NUMBER
);

INSERT INTO STATION VALUES ( 1, 'stationA', 'city1' );
INSERT INTO STATION VALUES ( 2, 'stationB', 'city1' );
INSERT INTO STATION VALUES ( 3, 'stationC', 'city2' );
INSERT INTO STATION VALUES ( 4, 'stationD', 'city3' );

INSERT INTO SERVICE VALUES ( 1337, 'train1' );
INSERT INTO SERVICE VALUES ( 1338, 'train2' );
INSERT INTO SERVICE VALUES ( 1339, 'train3' );

INSERT INTO ROUTE VALUES (1, 1337, 1, null, 1800);
INSERT INTO ROUTE VALUES (2, 1337, 2, 1900, 2000);
INSERT INTO ROUTE VALUES (3, 1337, 3, 2020, 2100);
INSERT INTO ROUTE VALUES (4, 1337, 4, 2120, 2200);
INSERT INTO ROUTE VALUES (5, 1338, 1, null, 1800);
INSERT INTO ROUTE VALUES (6, 1338, 4, 1900, 2000);
INSERT INTO ROUTE VALUES (7, 1338, 3, 2020, 2100);
INSERT INTO ROUTE VALUES (8, 1338, 2, 2120, 2200);

查询:

WITH INDEXED_ROUTES AS (
  SELECT train_number,
         s.name,
         ROW_NUMBER() OVER( PARTITION BY train_number ORDER BY COALESCE( arrival_time, 0 ), COALESCE( departure_time, 2400 ) ) AS IDX
  FROM   ROUTE r
          INNER JOIN
          STATION s
          ON ( r.station_id = s.id )
)
SELECT  train_number,
        SUBSTR( SYS_CONNECT_BY_PATH( NAME, ' -> ' ), 5 ) AS route
FROM    indexed_routes
WHERE CONNECT_BY_ISLEAF = 1
START WITH IDX = 1
CONNECT BY PRIOR IDX + 1 = IDX
AND        PRIOR train_number = train_number;

或者:

SELECT train_number,
       LISTAGG( s.name, ' -> ' ) WITHIN GROUP ( ORDER BY arrival_time ASC NULLS FIRST ) AS route
FROM   ROUTE r
        INNER JOIN
        STATION s
        ON ( r.station_id = s.id )
GROUP BY train_number;

要么输出:

TRAIN_NUMBER ROUTE
------------ --------------------------------------------
        1337 stationA -> stationB -> stationC -> stationD  
        1338 stationA -> stationD -> stationC -> stationB

如果您只想要成对的电台,请使用LAGLEAD分析函数:

SELECT train_number,
       LAG( s.name ) OVER( PARTITION BY train_number ORDER BY COALESCE( arrival_time, 0 ), COALESCE( departure_time, 2400 ) ) AS prev_station_name,
       s.name AS station_name
FROM   ROUTE r
        INNER JOIN
        STATION s
        ON ( r.station_id = s.id );

输出:

TRAIN_NUMBER PREV_STATION_NAME    STATION_NAME       
------------ -------------------- --------------------
        1337 (null)               stationA             
        1337 stationA             stationB             
        1337 stationB             stationC             
        1337 stationC             stationD             
        1338 (null)               stationA             
        1338 stationA             stationD             
        1338 stationD             stationC             
        1338 stationC             stationB      

答案 1 :(得分:1)

如果路径中没有分支,那么问题只是在到达或离开时间点订站:

SELECT s.station_id, name FROM ROUTE r INNER JOIN STATION s r.station_id = s.station_id ON WHERE train_number = 1 ORDER BY departure_time

答案 2 :(得分:1)

在MySQL中,您可以使用按到达时间排序的group_concat,以逗号分隔列表的形式获取每列火车的路径。

例如:

select train_number, group_concat(name order by arrival_time asc)
from route join station
  on route.station_id=station.id
group by train_number
order by train_number;

输出如下:

1337    stationA,stationB,stationC,stationD

在Oracle(来自11g第2版)中,以下查询将产生相同的输出:

select train_number,  LISTAGG(name, ',') WITHIN GROUP (ORDER BY arrival_time ASC NULLS FIRST)
from route join station
  on route.station_id=station.id
group by train_number
order by train_number;