选择满足某些条件且在某列中具有最大值的行

时间:2013-04-20 11:39:57

标签: sql postgresql greatest-n-per-group

我有一个用于更新软件包的元数据表。该表包含id, name, version列。我想选择名称是某个给定名称列表之一的所有行,并且版本是具有该名称的所有行的最大值。

例如,鉴于这些记录:

+----+------+---------+
| id | name | version |
+----+------+---------+
| 1  | foo  | 1       |
| 2  | foo  | 2       |
| 3  | bar  | 4       |
| 4  | bar  | 5       |
+----+------+---------+

任务“给我最高版本的记录”foo“和”bar“,我希望结果如下:

+----+------+---------+
| id | name | version |
+----+------+---------+
| 2  | foo  | 2       |
| 4  | bar  | 5       |
+----+------+---------+

到目前为止,我提出的是使用嵌套查询:

SELECT * 
  FROM updates 
  WHERE (
    id IN (SELECT id 
             FROM updates 
             WHERE name = 'foo' 
             ORDER BY version DESC 
             LIMIT 1)
  ) OR (
    id IN (SELECT id 
             FROM updates 
             WHERE name = 'bar' 
             ORDER BY version DESC 
             LIMIT 1)
  );

这有效,但感觉不对。如果我想过滤更多名称,我必须多次复制整个子查询。有更好的方法吗?

3 个答案:

答案 0 :(得分:4)

select distinct on (name) id, name, version
from metadata
where name in ('foo', 'bar')
order by name, version desc

答案 1 :(得分:3)

NOT EXISTS是一种避免不需要的次优元组的方法:

SELECT * 
FROM updates uu
WHERE uu.zname IN ('foo', 'bar')
AND NOT EXISTS (
    SELECT *
    FROM updates nx
    WHERE nx.zname = uu.zanme
    AND nx.version > uu.version
    );

注意:我已将name替换为zname,因为它是或多或少 postgresql中的关键字。

答案 2 :(得分:2)

重新阅读Q后更新:

  

我想选择所有行,其中名称是某个给定列表之一   名称和版本是具有该名称的所有行的最大值。

如果可以存在tie(多行具有每name的最大版本),则可以在子查询中使用窗口函数rank()。需要PostgreSQL 8.4 +。

SELECT *
FROM  (
   SELECT *, rank() OVER (PARTITION BY name ORDER BY version DESC) AS rnk
   FROM   updates 
   WHERE  name IN ('foo', 'bar')
   )
WHERE rnk = 1;