使用时间转换逻辑的高级SQL分析问题

Kru*_*sai 2 sql analytics

我有下面的表结构

Create Trains (
id int primary key,
origin varchar not null,
dest varchar not null,
departure_time varchar not null)

Create Passengers(
id int primary key,
origin varchar not null,
dest varchar not null,
departure_time varchar not null)

Trains
id  origin  dest  time
10  Beg     knp   10:20
20  Beg     knp   7:40
30  Del     Sin   12:05
40  Ghr     poh   13:40
50  Del     Sin   18:05

Passengers
id  origin  dest  time
101  Beg     knp   10:20
201  Beg     knp   7:00
301  Del     Sin   12:00
401  Ghr     poh   13:45
501  Del     Sin   19:05
Run Code Online (Sandbox Code Playgroud)

我想找出每列火车旅行的乘客人数

假设条件

  1. 即使乘客在相同的出发时间到达车站,也可以登上火车。即,即使他在12.05到达车站,他也可以登上12.05出发的火车

  2. 没有火车可以具有相同的出发地,目的地和出发时间。

  3. 乘客将在出发时间后赶上最早的火车

  4. 火车的始发地和目的地之间没有其他站点。

  5. 乘客只能搭乘从他的起点到目的地的直达火车。

谁能解释我如何解决这个问题?

我在下面写了查询-

select t.id,count(p.id) 
from p.passengers,t.trains 
where t.origin=p.origin and t.dest=p.dest 
    and cast(p.departure_time as time)<=cast(t.departure_time as time)
Run Code Online (Sandbox Code Playgroud)

我认为我没有考虑第三个假设。

h33*_*h33 5

确实没有一种简单的方法可以做到这一点。

当前查询的问题在于,它将乘客分配给所有在p.departure_time之后具有t.departure_time的列车,但是我们只希望乘客在p.departure_time之后乘坐第一列火车。

首先计算每个乘客可以搭乘的所有火车,然后将其范围缩小。

查询以选择乘客可以搭乘的所有火车:

SELECT *
FROM passengers p
LEFT JOIN trains t ON t.origin = p.origin AND t.dest = p.dest
    AND CAST(t.departure_time AS TIME) >= CAST(p.departure_time AS TIME)
Run Code Online (Sandbox Code Playgroud)

我们在上面的查询中,按passanger.id进行分组,然后选择最短出发时间(即,第一趟列车在乘客的走行时间之后或同一时间出发)。我们称此查询将捕获

SELECT p.id AS pid, MIN(CAST(t.departure_time AS TIME)) AS t_deptime
FROM passengers p
LEFT JOIN trains t ON t.origin = p.origin AND t.dest = p.dest
    AND CAST(t.departure_time AS TIME) >= CAST(p.departure_time AS TIME)
GROUP BY p.id
Run Code Online (Sandbox Code Playgroud)

最后的查询如下所示:

; WITH will_catch AS (
    SELECT p.id  pid, MIN(CAST(t.departure_time AS TIME)) AS t_deptime
    FROM passengers p
    LEFT JOIN trains t ON t.origin = p.origin AND t.dest = p.dest
        AND CAST(t.departure_time AS TIME) >= CAST(p.departure_time AS TIME)
    GROUP BY p.id
)
SELECT t.id, COUNT(t_deptime)
FROM will_catch wc
LEFT JOIN passengers p ON wc.pid = p.id
LEFT JOIN trains t ON (p.origin = t.origin AND p.dest = t.dest) 
    AND (wc.t_deptime = CAST(t.departure_time AS TIME) OR t_deptime IS NULL)
GROUP BY t.id
Run Code Online (Sandbox Code Playgroud)