【问题标题】:Run Postgres query that groups by one field and sorts by another运行按一个字段分组并按另一个字段排序的 Postgres 查询
【发布时间】:2016-04-14 15:15:33
【问题描述】:

我有一个包含以下相关字段的 PostgreSQL 表:

url
title
created_at

可以有许多行包含相同的 URL 但不同的标题。以下是一些示例行:

www.nytimes.com | The New York Times         | 2016-01-01 00:00:00`
www.wsj.com     | The Wall Street Journal    | 2016-01-03 15:32:13`
www.nytimes.com | The New York Times Online  | 2016-01-06 07:19:08`

我正在尝试获取列出以下字段的输出:

1) url
2)title对应created_at的最大值
3) 计数所有title 的唯一url

因此,上述示例的输出行将如下所示:

www.nytimes.com | The New York Times Online | 2
www.wsj.com     | The Wall Street Journal   | 1

根据我读过的关于类似问题的大量 SO 帖子,看起来我获得前两个字段(url 和最新的title)的最佳选择是使用DISTINCT ON

select distinct on (url) url, title from headlines order by url, created_at desc 

同样,要获得第一个和第三个字段(url 和所有title 的计数),我可以简单地使用GROUP BY

select url, count(title) from headlines group by url

我想不通的是如何结合上面的方法,得到上面我想要得到的三个值。

(经过编辑以提供更清晰的信息。)

【问题讨论】:

  • 如果您提供示例数据和预期输出将非常有帮助。
  • 自然连接你写的两个查询怎么样?
  • 技术上,“最近的名字”是greatest-n-per-group问题类的一部分。

标签: sql postgresql aggregate greatest-n-per-group window-functions


【解决方案1】:

这可以在单个SELECT 中完成,只需对表进行一次扫描 - 通过将window functionDISTINCT ON 结合使用:

SELECT DISTINCT ON (url)
       url, title, count(*) OVER (PARTITION BY url) AS ct 
FROM   headlines 
ORDER  BY url, created_at DESC NULLS LAST;

SQL Fiddle.

相关(附详细说明):

【讨论】:

    【解决方案2】:

    试试;

    select t1.url, t2.title, t1.cnt
    from (
      select url, count(title) cnt 
      from headlines 
      group by url
    ) t1
    join (
      select distinct on (url) url, title 
      from headlines 
      order by url, created_at desc
    ) t2 on t1.url = t2.url
    order by t1.url
    

    joinurl 上的两个查询

    sql fiddle demo

    【讨论】:

    • 我喜欢这两个答案(你的和@Erwin 的),但选择了这个,因为它在我的数据集上运行速度似乎稍快。
    • @jayp:最佳性能取决于您的设置和数据分布的细节。没有一个查询可以在每种情况下都表现最佳。 Details in the provided link .
    【解决方案3】:

    试试这个:

    select t1.url,t1.title,t2.count from headlines t1 
    inner join(
    select url,count(*) as count,max(created_at) as created_at
    from headlines group by url ) t2 on t1.url=t2.url and t1.created_at=t2.created_at;
    

    SQL 小提琴:http://sqlfiddle.com/#!15/f7665f/11

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多