Sql 通过分组获得最新记录

Sql 通过分组获得最新记录,sql,sql-server,oracle,group-by,greatest-n-per-group,Sql,Sql Server,Oracle,Group By,Greatest N Per Group,我有一个名为“结果”的表格,如下所示: 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

我有一个名为“结果”的表格,如下所示:

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子句或其他方法加入最大年数并获得相应的年数?我需要按数据对组进行2次操作,一次最新操作,以及相应的合格状态

附言:当然,在DB中有100个这样的候选人的记录


更新:根据答案2,该问题也被归类为每组最大n个问题。有趣的是,这是数据库中的一个分类问题。

在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,row_NUMBER()将返回一个随机行

仅在Oracle中,您就可以使用它来获得相同的结果:

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

在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,row_NUMBER()将返回一个随机行

仅在Oracle中,您就可以使用它来获得相同的结果:

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

这一直是一个重新设计的问题:

选择t1*
从结果中选择t1
左连接结果为t2
在t1.NAME=t2.NAME和t1.SUBJECT=t2.SUBJECT和t1.YEAR
这一直是一个重新设计的问题:

选择t1*
从结果中选择t1
左连接结果为t2
在t1.NAME=t2.NAME和t1.SUBJECT=t2.SUBJECT和t1.YEAR
谢谢!我跳过了有关分析/窗口功能的阅读。。。有人让我读一下。但是,我的Sublate问题是,我们是否可以使用aggregate函数,然后根据它从group_by中列出的“other”行检索parm。答案中的Oracle语法给出了您想要的@Nishant。不过,SQL Server不能这样做。我问的问题是否有任何技术术语,它基本上是一种条件,而不是分组中的另一种条件。只是好奇。have只是在一个组上检查一些东西,但是我们想收集一些匹配的东西,它不能被归类为谓词,等等,因为have在一个组上起作用。另外,如果我需要与Oracle MSSQL兼容的代码,我们需要使用我的解决方案?我认为它仍然是@Nishant的聚合函数,尽管还有一个额外的ORDER BY。您不必使用您的解决方案,正如您所提到的,它将意味着对表/索引进行两次扫描。您可以使用我最初建议的分析功能,它们与SQL Server和Oracle兼容(并且只涉及一次扫描)。谢谢!我跳过了有关分析/窗口功能的阅读。。。有人让我读一下。但是,我的Sublate问题是,我们是否可以使用aggregate函数,然后根据它从group_by中列出的“other”行检索parm。答案中的Oracle语法给出了您想要的@Nishant。不过,SQL Server不能这样做。我问的问题是否有任何技术术语,它基本上是一种条件,而不是分组中的另一种条件。只是好奇。have只是在一个组上检查一些东西,但是我们想收集一些匹配的东西,它不能被归类为谓词,等等,因为have在一个组上起作用。另外,如果我需要与Oracle MSSQL兼容的代码,我们需要使用我的解决方案?我认为它仍然是@Nishant的聚合函数,尽管还有一个额外的ORDER BY。您不必使用您的解决方案,正如您所提到的,它将意味着对表/索引进行两次扫描。您可以使用我最初建议的分析函数,它们与SQL Server和Oracle兼容(并且只涉及一次扫描)。感谢您指出问题所在,它甚至还有一个名称!正如Ben所说,我也担心2次索引扫描不是解决这个问题的理想方法。你们都是对的,还有其他非常有趣的解决方案(比如@Ben的解决方案)可能更快。。。。。但是要小心@Nishant,这些不是便携的!所有主要的RDBMS bar MySQL都提供了窗口功能,所以说它“不可移植”有点误导。它将在DB2、Oracle、Postgres、SQL Server、Sybase、Informix、Teradata和(我相信)Firebird 3上工作。它们也是解决这个问题的标准方法,同样,在每个RDBMS中,除了MySQL之外,它们都是获取数据的最快方法。唯一可能的例外是Oracle,它是SQL标准的非标准keep dense_rank扩展,比窗口/分析函数更快、更高效。@Nishant没问题,Bens的答案是最好的-我只是想确保您知道这不是可移植的解决方案。感谢您指出问题,它甚至还有一个名字!正如Ben所说,我也担心2次索引扫描不是解决这个问题的理想方法。你们都是对的,还有其他非常有趣的解决方案(比如@Ben的解决方案)可能更快。。。。。但是要小心@Nishant,这些不是便携的!所有主要的RDBMS bar MySQL都提供了窗口功能,所以说它“不可移植”有点误导。它将在DB2、Oracle、Postgres、SQL Server、Sybase、Informix、Teradata和(我相信)Firebird 3上工作。它们也是解决这个问题的标准方法,同样,在每个RDBMS中,除了MySQL之外,它们都是获取数据的最快方法。唯一可能的例外是甲骨文,它是一家非标准的公司