按最大值选择多行

时间:2011-10-03 14:43:13

标签: sql oracle

我有一个带有“版本控制”方案的简单表:

Version | PartKey1 | PartKey2 | Value
   1    |    0     |    0     | foo
   2    |    0     |    0     | bar
   1    |    1     |    0     | foobar

此表格中等(完整版约100 000行)。在开始时,它加载了包含完整快照的版本1,并且随着时间的推移添加了增量更新,但我们希望保留旧版本,因此它们会添加一个递增的“版本”编号(此处为2)。 / p>

在阅读数据时,我希望能够指定最大版本,如果可能的话,我希望只检索我感兴趣的“行”。

例如:指定2作为最大版本,我想在上表中只检索2行的查询:

Version | PartKey1 | PartKey2 | Value
   2    |    0     |    0     | bar
   1    |    1     |    0     | foobar

行:

   1    |    0     |    0     | foo

被丢弃,因为此行的版本2 更新。

我想知道在SQL查询中这样的选择是否可行/可取。我可以在应用程序端进行过滤,但显然这意味着从数据库中提取无用的资源,所以如果可能(并且在数据库方面便宜),我宁愿将这项工作卸载到数据库。

3 个答案:

答案 0 :(得分:5)

你可以这样做:

SELECT v1.*
  FROM versioningscheme v1
  LEFT JOIN versioningscheme v2
    ON v2.partkey1 = v1.partkey1 AND v2.partkey2 = v1.partkey2
   AND v2.version > v1.version
 WHERE v2.version IS NULL

使用NULL检测的左连接非常强大且未充分利用。当没有匹配时返回空值(显然,当你在v1中有最大行时,你不能在v2中获得满足连接条件的行)。

答案 1 :(得分:2)

select t.*
from MyTable t
inner join (
    select PartKey1, PartKey2, max(Version) as MaxVersion
    from MyTable
    where Version <= 2
    group by PartKey1, PartKey2
) tm on t.PartKey1 = tm.PartKey1 
    and t.PartKey2 = tm.PartKey2 
    and t.Version = tm.MaxVersion

答案 2 :(得分:2)

这适用于时变数据(您选择在特定时间窗口内查找最新值),这是完全合理的。

在您的情况下,ROW_NUMBER()允许仅解析一次数据,而不是多次。使用适当的INDEX,例如(PartKey1, PartKey2, Version),这应该非常快......

SELECT
  *
FROM
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY PartKey1, PartKey2 ORDER BY Version DESC) AS reversed_version
  FROM
    MyTable
  WHERE
    Version <= <MaxVersionParamter>
)
  AS data
WHERE
  reversed_version = 1