sql - 选择 group by 中的第一行或随机行

标签 sql postgresql

我使用 PostgreSQL 9.1(我们的托管平台升级后立即使用 9.2)进行此查询:

SELECT
    media_files.album,
    media_files.artist,
    ARRAY_AGG (media_files. ID) AS media_file_ids
FROM
    media_files
INNER JOIN playlist_media_files ON media_files.id = playlist_media_files.media_file_id
WHERE
    playlist_media_files.playlist_id = 1
GROUP BY
    media_files.album,
    media_files.artist
ORDER BY
    media_files.album ASC

它工作正常,目标是提取专辑/艺术家组合,并在结果集中为该特定组合提供一系列媒体文件 ID。

问题是我在媒体文件中有另一列,它是 artwork .
artwork对于每个媒体文件(即使在同一个专辑中)都是唯一的,但在结果集中我只需要返回集合中的第一个。

因此,对于包含 10 个媒体文件的专辑,我也有 10 个相应的艺术品,但我只想返回第一个(或为该集合随机挑选的一个)。

是否可以仅使用 SQL/窗口函数(first_value 超过 ..)?

最佳答案

是的,这是可能的。首先,让我们通过添加别名和显式列限定符来调整您的查询,以便清楚什么来自哪里 - 假设我猜对了,因为没有表定义我无法确定:

SELECT
    mf.album,
    mf.artist,
    ARRAY_AGG (mf.id) AS media_file_ids
FROM
    "media_files" mf
INNER JOIN "playlist_media_files" pmf ON mf.id = pmf.media_file_id
WHERE
    pmf.playlist_id = 1
GROUP BY
    mf.album,
    mf.artist
ORDER BY
    mf.album ASC

现在您可以在 SELECT 中使用子查询列出或使用 DISTINCT ON ,虽然它看起来像任何基于 DISTINCT ON 的解决方案会如此复杂以至于不值得。

你真正想要的是类似 pick_arbitrary_value_agg 的东西聚合只是选择它看到的第一个值并将其余的扔掉。没有这样的聚合,并且它真的不值得为工作而实现。您可以使用 min(artwork)max(artwork)您可能会发现这实际上比后面的解决方案性能更好。

要使用子查询,请留下 ORDER BY按原样添加以下内容作为您的 SELECT 中的额外列列表:
(SELECT mf2.artwork 
 FROM media_files mf2 
 WHERE mf2.artist = mf.artist
   AND mf2.album = mf.album
 LIMIT 1) AS picked_artwork

您可以通过添加 ORDER BY random() 以牺牲性能为代价随机化选定的艺术品。之前LIMIT 1以上。

或者,这里有一种快速而肮脏的方式来实现内联随机行的选择:
(array_agg(artwork))[width_bucket(random(),0,1,count(artwork)::integer)] 

由于没有样本数据,我无法测试这些修改。让我知道是否有问题。

关于sql - 选择 group by 中的第一行或随机行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13853569/

相关文章:

sql - XML 解析错误 非法限定名称字符

sql - Postgres 查询以查找所有从属表

mysql - 按路径和排序顺序获取类别树

sql - 显示表,其中外键是引用表第二列的值

sql - PostgreSQL 选择

sql - 计算不同组合的查询

sql - 使用触发器计算SQLite中行之间的差异

sql - 使用复杂的双连接来获取子对象的数量

database - 获取日期范围内每天仅存在一次的唯一记录

postgresql - Postgres 选择慢得多的序列扫描而不是索引扫描