按另一个表中的属性排序SQL结果

时间:2016-01-14 05:59:40

标签: sql postgresql

如果我有一张包含许多停靠点的总线表,并且每个停靠记录都有到达时间,我该如何在最早的停止时间内检索和订购总线?

 _______    ________
| 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,这会让我有不同停靠时间的重复巴士。

进行此查询的更好方法是什么?

4 个答案:

答案 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
  • nb:这与Susilo的答案完全相同,除了我使用过 列中的列别名为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
;
  • 提示:如果您在查询要求中看到/听到“最早”或“最新” 那么这种技术经常适用。