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

问题描述 投票:2回答:4

我有下面的表格结构

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

我正在尝试查找每列火车旅行的乘客数

假设

  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)

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

sql analytics
4个回答
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)

我们接受上面的查询,将其按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

最后的查询看起来像这样:

; 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

0
投票

您可以使用相关子查询:

select p.*,
       (select t.id
        from trains t
        where t.origin = p.origin and t.dest = p.dest and
              cast(t.time as time) >= cast(p.time as time)
        order by cast(t.time as time) desc
        fetch first 1 row only
       ) as train_id
from passengers p;

请注意,这使用ANSI / ISO语法从子查询中获取一行。在特定的数据库(top 1limit 1等)中,这可能有所不同。


0
投票
select t.id, count(sub2.pass_id) no_of_passenger from trains t 
left outer join 
(select min(sub.t2) time, sub.id1 pass_id, sub.org, sub.des 
from 
(select p.id id1, t.id id2, t.origin org, t.destination des, p.time t1 , t.time t2 from trains t join
passengers p 
on t.origin = p.origin and t.destination = p.destination and t.time >= p.time
order by p.id, t.time)sub
group by sub.id1, sub.org, sub.des) sub2 
on t.origin = sub2.org and t.destination = sub2.des  and t.time = sub2.time
group by t.id
order by t.id
;

0
投票

更简单的方法:

将tr1.id选择为train_id,总和(从tr1火车的number_of_passenger中获取number_of_passenger的情况(passenger_with_train.passenger_id为null则为0否则1结束的情况)左外连接(从乘客p中选择p.id作为passenger_id,选择tr.id作为train_id交叉应用(从火车t中选择top(1)t.id,其中p.dest = t.dest和t.origin = p.origin且t.departure_time> = p.departure_time按t.departure_time asc的顺序排序)tr)作为passenger_with_train在tr1.id =乘tr1.id的passenger_with_train.train_id组

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.