查找多个列的最大值

时间:2014-04-20 05:45:06

标签: sql oracle11g

我正在尝试查询最近一个学期的会议列表,其中学期由两个字段(年,学期)决定。这是架构的基本概要:

Otherfields    Year    Semester
meeting1       2014    1
meeting2       2014    1
meeting3       2013    2
... etc ...

由于最初应考虑年份,而然后学期,我的结果应如下所示:

Otherfields    Year    Semester
meeting1       2014    1
meeting2       2014    1

不幸的是,单独在每列上使用MAX()函数会尝试查找Year = 2014,Semester = 2,这是不正确的。我尝试了几种使用嵌套子查询和内部联接的方法,但是无法完成某些工作。解决这个问题最简单的方法是什么?

6 个答案:

答案 0 :(得分:2)

使用窗口功能:

SELECT Year, Semester, RANK() OVER(ORDER BY Year DESC, Semester DESC) R
FROM your_table;

R将是一个包含" rank"的列。这对夫妇(年,学期)。然后,您可以将此列用作过滤器,例如:

WITH TT AS (
  SELECT Year, Semester, RANK() OVER(ORDER BY Year DESC, Semester DESC) R
  FROM your_table
)
SELECT ...
FROM TT
WHERE R = 1;

如果您不希望排名之间存在差距,则可以使用dense_rank代替rank

这个答案假设您使用的RDBMS足够先进,可以提供窗口功能(即不是MySQL)

答案 1 :(得分:1)

如果有更有效的方法(并避免重复的子查询),我不会感到惊讶,但这会得到你想要的答案:

SELECT * FROM table WHERE Year = 
    (SELECT MAX(Year) FROM table)
AND Semester =
    (SELECT MAX(Semester) FROM table WHERE Year =
        (SELECT MAX(Year) FROM table))

答案 2 :(得分:1)

这是Postgres:

with table2 as /*virtual temporary table*/
(
    select *, year::text || semester as yearsemester
    from table
)
select Otherfields, year, semester
from table2
where (Otherfields, yearsemester) in
(
    select Otherfields, max(yearsemester)
    from table2
    group by Otherfields
)

答案 3 :(得分:1)

我一直在思考这个问题,有一个更简单的方法来解决这个问题:

SELECT Meeting.year, Meeting.semester, Meeting.otherFields
FROM Meeting
JOIN (SELECT year, semester
      FROM Meeting
      WHERE ROWNUM = 1
      ORDER BY year DESC, semester DESC) MostRecent
  ON MostRecent.year = Meeting.year
     AND MostRecent.semester = Meeting.semester

(和working Fiddle

请注意,这种变体应该适用于所有 dbs(支持子查询中的限制子句的任何内容);这是MySQL版本,例如:

SELECT Meeting.year, Meeting.semester, Meeting.otherFields
FROM Meeting
JOIN (SELECT year, semester
      FROM Meeting
      ORDER BY year DESC, semester DESC
      LIMIT 1) MostRecent
  ON MostRecent.year = Meeting.year
     AND MostRecent.semester = Meeting.semester

(......和working fiddle

鉴于一些数据in this answer,这对Oracle应该是高性能的,我也怀疑其他dbs(考虑到优化器允许的快捷方式)。在没有提供分区子句的大多数情况下(无窗口),这应该能够替换ROW_NUMBER()之类的东西。

答案 4 :(得分:0)

为什么不简单地使用ORDER BY ???

这样,它会更容易处理,而且不那么凌乱! :)

SELECT * FROM table
Where Year = (Select Max(Year) from table) /* optional clause to select only 2014*/
Order by Semester ASC, Year DESC,  Otherfields; /*numericaly lowest sem first. in case of sem clash, sort by descending year first      */   

修改

如果您需要2014年的有限结果,请使用Limit子句( for mysql

SELECT * FROM table
Where Year = (Select Max(Year) from table) 
Order by Semester ASC, Year DESC,  Otherfields
LIMIT 10;

首先order,然后获得限制 - 10,所以你得到有限的结果集!

这将获取如下输出:

Otherfields    Year    Semester
meeting1       2014    1
meeting2       2014    1
meeting1       2013    1
meeting2       2013    2

答案 5 :(得分:0)

在这里回答我自己的问题:

此查询是在存储过程中运行的,因此我继续在查询的其余部分之前在单独的查询中找到最大年份/学期。这很可能是效率低下且不优雅的,但它也是最容易理解的方法 - 我不需要担心我的团队中的其他成员会对此感到困惑。我会在这里留下这个问题,因为它通常适用于许多其他情况,似乎有一些很好的答案提供替代方法。

-- Find the most recent year.
SELECT MAX(year) INTO max_year FROM meeting;

-- Find the most recent semester in the year.
SELECT MAX(semester) INTO max_semester FROM meeting WHERE year = max_year;

-- Open a ref cursor for meetings in most recent year/semester.
OPEN meeting_list FOR
    SELECT otherfields, year, semester
    FROM   meeting
    WHERE  year = max_year
    AND    semester = max_semester;