2013-04-20 81 views
4

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

例如,考虑到这些记录:

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

和任务“给我的记录,最高版本的‘富’与‘酒吧’,我希望得到的结果是:

+----+------+---------+ 
| 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) 
); 

这工作,但感觉错了。如果我要过滤。更多的名字,我必须多次复制整个子查询。有一个更好的方法吗?

+0

我去到回答的情况下(如已澄清):http://stackoverflow.com/questions/3800551/sql-select-first-row-in-each-group-by-group/7630564#7630564 – 2013-04-20 12:50:47

回答

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

我是'DISTINCT ON'的忠实粉丝,但在查找“所有行”时它不是正确的工具 - 可能包含重复的名称。更重要的是:这会为通过WHERE子句的* every *'name'检索一行(带有最大版本),这与问题所要求的AIUI略有不同。 – 2013-04-20 12:11:09

+0

这似乎是做我想做的,看起来迄今为止所有答案中最简单的,所以我接受它。谢谢! – adam 2013-04-20 12:15:26

+1

@adam:重新阅读后,我发现我似乎误解了你的问题。 – 2013-04-20 12:16:26

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 
    ); 

注:我通过zname取代name,因为它是或多或少 PostgreSQL中的关键字。重读将q后

+0

'name' [*不是一个保留字](http://www.postgresql.org/docs/current/interactive/sql-keywords-appendix.html),但将它作为标识符,因为它不具有描述性。 – 2013-04-20 11:57:38

+0

我以为它被用作旧版本中表和列名称的类型名称。但是,也许我只是想用'z'来加前缀...... – wildplasser 2013-04-20 12:10:25

+0

此外,更重要的是,我认为查询是*不正确*,就像@ Clodoaldo的查询一样。它获取每个名称的最大版本*,而不是具有所有行*的最大值的行。 – 2013-04-20 12:15:09

2

更新:

我想选择所有行其中名字为名称的一些定列表 之一,该版本最大的所有行的使用该名称

如果可以有关系(每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; 
相关问题