【问题标题】:PostgreSQL - how to find top routes (records where 2 columns are the same)? [closed]PostgreSQL - 如何找到顶级路线(两列相同的记录)? [关闭]
【发布时间】:2020-10-09 22:17:38
【问题描述】:

我有一个简单的 Ruby On Rails 应用程序来管理行程。这是我存储在数据库中的数据示例:

id | origin     | destination | ...
 1 | London, UK | Prague, CZ  | ...
 2 | Paris, FR  | Berlin, GE  | ...
 3 | Berlin, GE | Munich, GE  | ...
 4 | Berlin, GE | Moscow, RU  | ...
 5 | Rome, IT   | Florence, IT  | ...
 6 | London, UK | Prague, CZ  | ...
 7 | Paris, FR  | Berlin, GE  | ...
 8 | Paris, FR  | Berlin, GE  | ...

我想找到最热门的行程,所以想要的输出是这样的:

Paris, FR  | Berlin, GE  | 3x
London, UK | Prague, CZ  | 2x
Berlin, GE | Munich, GE  | 1x
Berlin, GE | Moscow, RU  | 1x
Rome, IT   | Florence, IT  | 1x

我如何实现这一目标?我有一个包含 300k 行程的数据库,对于大多数行程,我还存储了 lat+long 坐标 - 但在这种情况下,不确定将起点和目的地作为字符串搜索还是通过坐标搜索字段更好。

提前谢谢你!

【问题讨论】:

  • 你是如何实现的? “热门旅行”的实际指标是什么?最受欢迎?可乐最多的那个?

标签: sql ruby-on-rails postgresql count sql-order-by


【解决方案1】:

答案基于您当前的数据库设计:

Trip.select('origin, destination, count(*) as trips_count')
    .group(:origin, :destination).order('trips_count desc')

如果您想在查询中包含航空公司,可以使用array_agg function

Trip.select('origin, destination, count(*) as trips_count, array_agg(distinct(airline)) as airlines')
    .group(:origin, :destination).order('trips_count desc')

我建议将origindestination 列移动到它们自己的表中,例如routes 表,并将trips 表中的这些列替换为route_id。您还可以在 routes 表上实现 trips_count counter_cache 并按该列排序以获得最受欢迎的路线。

【讨论】:

  • 嗨@AbM,谢谢!我已经使用了它并进行了一些细微的修改。我只是想知道-每次旅行都有一个承运人。在此查询中,我是否还可以列出运营商,例如。 Paris, FR | Berlin, GE | 3x | Lufthansa, KLM(在本例中,2 趟 KLM,1 趟 Lufthansa)?
  • @user984621我根据您的评论更新我的答案
【解决方案2】:

您可以聚合、计数和排序:

select origin, destination, count(*) cnt
from mytable
group by origin, destination
order by cnt desc

然后,您可以使用limit 子句控制查询返回的路由数量。假设您想要 5 条最频繁的路线,那么:

select origin, destination, count(*) cnt
from mytable
group by origin, destination
order by cnt desc
limit 5

但请注意,这并未考虑潜在的联系。如果您对此感兴趣,那么解决方案取决于您的 Postgres 版本。在最新版本(Postgres 13)中:

select origin, destination, count(*) cnt
from mytable
group by origin, destination
order by cnt desc
fetch first 5 rows with ties

在早期版本中:

select origin, destination, cnt
from (
    select origin, destination, count(*) cnt, rank() over(order by count(*) desc) rn
    from mytable
    group by origin, destination
) t
where rn <= 5
order by cnt desc

【讨论】:

    猜你喜欢
    • 2020-07-14
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 2021-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 1970-01-01
    相关资源
    最近更新 更多