SQL查询-根据时刻表获取到站和出发站

Nim*_*a G 1 sql oracle

我有以下表格:

  • 路线(id、train_number、station_id、到达时间、出发时间)
  • SERVICE (train_number, train_name)
  • STATION (id, name, city)

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

我想找出每个 train_number 的路径。我的困难在于找出每条路线的到达和出发站名称。

例如火车 1337 可能有以下路径:

  • A站 -> B站:
    • 路线(1、1337、a站、空、1800)
    • 路线(2, 1337, stationB, 1900, 2000)
  • B站->C站:
    • 路线(3, 1337, stationC, 2020, 2100)
  • 站C -> 站D:
    • 路线(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
Run Code Online (Sandbox Code Playgroud)

MT0*_*MT0 5

设置:

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);
Run Code Online (Sandbox Code Playgroud)

询问:

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;
Run Code Online (Sandbox Code Playgroud)

或者:

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;
Run Code Online (Sandbox Code Playgroud)

要么输出:

TRAIN_NUMBER ROUTE
------------ --------------------------------------------
        1337 stationA -> stationB -> stationC -> stationD  
        1338 stationA -> stationD -> stationC -> stationB
Run Code Online (Sandbox Code Playgroud)

如果您只需要成对的站,请使用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 );
Run Code Online (Sandbox Code Playgroud)

输出:

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      
Run Code Online (Sandbox Code Playgroud)