如果我有一张包含许多停靠点的总线表,并且每个停靠记录都有到达时间,我该如何在最早的停止时间内检索和订购总线?
_______ ________
| Buses | | Stops |
|-------| |--------|
| id | | id |
| name | | bus_id |
------- | time |
--------
我可以使用以下查询来执行此操作:
SELECT DISTINCT sub.id, sub.name
FROM
(SELECT buses.*, stops.time
FROM buses
INNER JOIN stops ON stops.bus_id = buses.id
ORDER BY stops.time) AS sub;
...但是这有缺点是必须进行2次查询并且必须在SELECT DISTINCT子句中指定总线中的所有字段。如果巴士表发生变化,那会特别烦人。
我想做的是:
SELECT DISTINCT buses.*
FROM buses
INNER JOIN stops ON stops.bus_id = buses.id
ORDER BY stops.time;
...但是为了获得DISTINCT buses.*
,我必须在那里加入stops.time
,这会让我有不同停靠时间的重复巴士。
进行此查询的更好方法是什么?
答案 0 :(得分:3)
您可以做的一件事是将内部查询放入ORDER BY
。这将保持外部查询"清洁"因为它只会从公共汽车中选择。这样您就不需要返回任何其他字段。
SELECT buses.*
FROM buses
ORDER BY (
SELECT MIN(stops.time) FROM stops WHERE stops.bus_id = buses.id
)
答案 1 :(得分:2)
在select中指定字段是最佳做法,因此我不确定为什么将其列为缺点。
我愿意
Select buses.* From buses inner join
(Select stops.bus_id, min(stops.time) as mintime
From Stops
Group By stops.bus_id) st on buses.id = st.bus_id
或
Select buses.*, min(stops.time) as stoptime
From buses inner join stops on
buses.ID = stops.bus_ID group by buses.id, buses.name
答案 2 :(得分:1)
我没有postgresql,但我认为这个问题中的问题对于任何SQL都是通用的 问题是DISTINCT将从不提供正确的解决方案,因为将列出表停止的所有停止时间。
要获得正确的解决方案,我们可以使用GROUP BY和MIN ..
SELECT B.id, B.name, MIN(S.time) MinTime
FROM
Buses B INNER JOIN Stops S
ON B.id = S.bus_id
GROUP BY B.id, B.name
ORDER BY MIN(S.time)
答案 3 :(得分:1)
我想打开声明“选择不同”被过度使用并且通常很难理解。这是一个非常有限的工具,如果您已经使用它并且查询仍然无法满足您的需求,那么接下来要使用的两个工具是 1。 GROUP BY 和 2。 ROW_NUMBER()强>
在这个需要的列数不多的示例中,GROUP BY将非常容易地生成所需的结果:
SELECT
B.id
, B.name
, MIN(S.time) MinTime
FROM Buses B
INNER JOIN Stops S ON B.id = S.bus_id
GROUP BY
B.id
, B.name
ORDER BY
MinTime
这是一种有效的替代方法,在您需要某一行的所有列时很有用,例如代表“最早停止时间”的行是使用ROW_NUMBER()
SELECT
id
, name
, time
FROM (
SELECT
B.id
, B.name
, S.time
, ROW_NUMBER() OVER (PARTITION BY B.id ORDER BY S.time ASC) AS rowno
FROM Buses B
INNER JOIN Stops S ON B.id = S.bus_id
) dt
WHERE rowno = 1
ORDER BY
Time
;