2013-06-29 100 views
1

我有一个表叫做结果是这样的:HAVING - GROUP BY获得的最新记录

RESULTS_IDN NAME SUBJECT YEAR QUALIFIED 
1    MARK ENGLISH 1989 N 
3    MARK ENGLISH 1991 N 
5    MARK ENGLISH 1993 Y 
7    MARK ENGLISH 1995 N 
2    MARK MATH  1990 N 
5    MARK MATH  1993 N 
6    MARK MATH  1995 Y 
4    MARK SCIENCE 1991 N 
9    MARK SCIENCE 1997 Y 

我需要知道候选人为最新的考试对象的资质状况,他写了,怎么我可以写这个(ORACLE/MSSQL)的查询吗?

例如输入

NAME,SUBJECT OUTPUT NAME IDN SUBJECT YEAR Q 
MARK,ENGLISH OUTPUT MARK 7 ENGLISH 1995 N 
MARK SCIENCE OUTPUT MARK 9 SCIENCE 1997 Y 
MARK MATH  OUTPUT MARK 6 MATH 1995 Y 

我知道的一种方式来解决这个问题。

(SELECT NAME SUBJECT YEAR MAX(YEAR) YEAR 
FROM RESULTS WHERE NAME = 'MARK' AND SUBJECT ='MATH' 
GROUP BY NAME SUBJECT YEAR) LATEST 

将上面的表返回到同一张表的IDN,我可以得到结果。但这是双重工作。无论如何,我可以使用HAVING CLAUSE或其他东西来使用MAX(YEAR)并获得相应的年份?我需要对GROUP BY数据进行2次操作,一次最新操作以及符合条件的合格状态。

PS:当然在DB中有100个这样的候选人的记录。

更新:此问题也被归类为最大的每组问题根据答案2.有趣的是知道它是DB中的分类问题。

回答

3

在Oracle和SQL Server,您可以使用分析/窗口化功能RANK()或ROW_NUMBER()来实现这一目标:

select * 
    from (select a.* 
       , rank() over (partition by name, subject order by year desc) rnk 
      from ... a 
       ) 
where rnk = 1 

RANK()将返回1的每一行即每最新namesubject,ROW_NUMBER()将返回一个随机行。

在Oracle只有你可以使用KEEP给你同样的结果:

select name, subject, max(year) as year 
    , max(qualified) keep (dense_rank first order by year desc) as qualified 
    from ... 
group by name, subject 
+0

谢谢!我跳过了关于分析/窗口功能的阅读......有人让我阅读。 – Nishant

+0

但是,我的sublte问题是,我们是否可以使用聚合函数,然后根据group_by中包含的“其他”行中的值检索parm。 – Nishant

+1

答案中的Oracle语法提供了您要求的@Nishant。尽管如此,你不能用SQL Server来做到这一点。 – Ben

1

这是所有的时间彻底改造的问题:

SELECT t1.* 
FROM RESULTS AS t1 
LEFT JOIN RESULTS AS t2 
    ON t1.NAME = t2.NAME AND t1.SUBJECT = t2.SUBJECT AND t1.YEAR < t2.YEAR 
WHERE t2.NAME IS NULL 
+1

有没有必要做两个索引扫描虽然... – Ben

+0

感谢您指出的问题,它甚至有一个名字!正如Ben所说,我也对2个索引扫描感到担忧,这对于这个问题来说不是理想的要求。 – Nishant

+0

那么你是正确的,还有其他非常有趣的解决方案(如@Ben之一),可能会更快。 – TMS