Oracle查询 - 选择热门记录

时间:2013-12-03 22:15:47

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

假设下表:

ID    Name    Revision
---   -----   --------
 1    blah     0
 2    yada     1
 3    blah     1
 4    yada     0
 5    blah     2
 6    blah     3

如何获得两个记录,一个用于“blah”,另一个用于“yada”,最高版本号(3个用于blah,1个用于yada)?类似的东西:

ID    Name    Revision
---   -----   --------
 6    blah     3
 2    yada     1

此外,一旦检索到这些记录,如何按名称和修订排序?

我正在尝试创建一个主 - 详细信息视图,其中主记录是最新版本,详细信息包括以前的修订版。

3 个答案:

答案 0 :(得分:5)

基本上,使用汇总功能MAX()

SELECT "Name", MAX("Revision") AS max_revison
FROM   tbl
WHERE  "Name" IN ('blah', 'yada');
GROUP  BY "Name"
ORDER  BY "Name";   -- ordering by revision would be pointless;

如果您需要从行中更多列,有几种方法。一种方法是将上面的子查询连接回基表:

SELECT t.*
FROM (
   SELECT "Name", max("Revision") AS max_revison
   FROM   tbl
   WHERE  "Name" IN ('blah', 'yada');
   GROUP  BY "Name"
   ) AS sub
JOIN  tbl AS t ON t."Revision" = sub.max_revison
              AND t."Name" = sub."Name"
ORDER BY "Name";

通常,如果“修订版”不是唯一的(每个“名称”),则有可能每"Name"多行。您必须定义如何从共享相同最大“修订版”的一组对等方中挑选one - 一个决胜局。

另一种方法是 NOT EXISTS ,不包括具有更多同行的行,可能更快:

SELECT t.*
FROM   tbl AS t
WHERE  "Name" IN ('blah', 'yada')
AND    NOT EXISTS (
   SELECT 1
   FROM   tbl AS t1
   WHERE  t1."Name" = t."Name"
   AND    t1."Revision" > t."Revision"
   )
ORDER  BY "Name";

或者您可以将 CTE 与分析函数(窗口函数)一起使用:

WITH cte AS (
   SELECT *, ROW_NUMBER() OVER(PARTITION BY "Name" ORDER BY "Revision" DESC) AS rn
   FROM   tbl
   WHERE  "Name" IN ('blah', 'yada')
   )
SELECT *
FROM   cte
WHERE  rn = 1;

最后一个略有不同:保证每"Name"一行。如果您不使用更多ORDER BY项,则在绑定时将选择任意行。如果您希望所有同行改为使用RANK()

答案 1 :(得分:2)

此方法将为每个Name选择具有该Name的最大修订号的行。结果将是您在帖子中寻找的确切输出。

SELECT *
FROM tbl a
WHERE a.revision = (select max(revision) from tbl where name = a.name)
ORDER BY a.name

答案 2 :(得分:1)

在Oracle中,您可以使用LAST函数来简化此操作。

select max(id) keep (dense_rank last order by revision),
       name,
       max(revision)
from table
group by name;

Demo