SQL查询:返回组的最大值记录

Posted

技术标签:

【中文标题】SQL查询:返回组的最大值记录【英文标题】:SQL Query: Return Max value record of a Group 【发布时间】:2019-08-02 14:42:01 【问题描述】:

我有一个类似结构和数据的示例表,如下所示:

+------+---------+-------------+------------+
| S_ID | S_NAME  | SUBJECT     | MARK_VALUE |
+------+---------+-------------+------------+
|    1 | Stud    | SUB_1       |         50 |
|    2 | Stud    | SUB_2       |         60 |
|    3 | Stud    | SUB_3       |         70 |
|    4 |  Stud_1 | SUB_1       |         40 |
|    5 |  Stud_1 | SUB_2       |         50 |
|    6 |  Stud_2 | SUB_2       |         40 |
+------+---------+-------------+------------+

表格有每个学生在所有科目中出现的每个学生的综合分数。

请帮我写一个查询来提取每个学生获得的最高分数(不分学科/其他学生),如下所示:

按 S_Name 和 Max(MARK_Value) 分组

+------+---------+-------------+------------+
| S_ID | S_NAME  | SUBJECT     | MAX_MARK   |
+------+---------+-------------+------------+
|    3 | Stud    | SUB_3       |         70 |
|    5 |  Stud_1 | SUB_2       |         50 |
|    6 |  Stud_2 | SUB_2       |         40 |
+------+---------+-------------+------------+

【问题讨论】:

【参考方案1】:

您可以使用group bykeep

select max(s_id) keep (dense_rank first order by mark desc) as s_id,
       s_name,
       max(subject) keep (dense_rank first order by mark desc) as subject,
       max(max_mark)
from t
group by s_name;

keep 是一个 Oracle 扩展,它允许将 first_value()last_value() 等功能用于聚合函数。根据我的经验,它非常快。

【讨论】:

【参考方案2】:

请试试这个。

Select B.* from @tbl AS B
INNER JOIN(
Select S_Name,MAX(MARK_VALUE) AS MARK_VALUE   from @tbl Group by S_Name) AS A
ON A.S_name=B.S_Name
AND A.MARK_VALUE = B.MARK_VALUE

【讨论】:

【参考方案3】:

解析函数ROW_NUMBER 可用于按S_NAME 对行进行分组(因为您想获得每个学生的最高分数),并按降序对分数进行排序,以便最大值上升到顶部(即得到 行号 = 1)。

然后选择具有该行号值的行。

SQL> with test (s_id, s_name, subject, mark_value) as
  2    (select 1, 'stud', 'sub_1'  , 50 from dual union all
  3     select 2, 'stud', 'sub_2'  , 60 from dual union all
  4     select 3, 'stud', 'sub_3'  , 70 from dual union all
  5     select 4, 'stud_1', 'sub_1', 40 from dual union all
  6     select 5, 'stud_1', 'sub_2', 50 from dual union all
  7     select 6, 'stud_2', 'sub_2', 40 from dual
  8    )
  9  select s_id, s_name, subject, mark_value
 10  from (select s_id, s_name, subject, mark_value,
 11               row_Number() over (partition by s_name order by mark_value desc) rn
 12        from test
 13       )
 14  where rn = 1;

      S_ID S_NAME SUBJE MARK_VALUE
---------- ------ ----- ----------
         3 stud   sub_3         70
         5 stud_1 sub_2         50
         6 stud_2 sub_2         40

SQL>

如果您的数据库版本不支持分析功能,还有另一个选项不太好,因为它从同一个表中选择了两次。如果表中的行数不多,您不会注意到差异,但在大型数据集上性能会受到影响。

 <snip>
  9  select s_id, s_name, subject, mark_value
 10  from test
 11  where (s_name, mark_value) in (select s_name, max(mark_value) max_mark
 12                                 from test
 13                                 group by s_name);

      S_ID S_NAME SUBJE MARK_VALUE
---------- ------ ----- ----------
         3 stud   sub_3         70
         5 stud_1 sub_2         50
         6 stud_2 sub_2         40

SQL>

【讨论】:

【参考方案4】:

使用row_number()窗口函数

select * from
 ( select *,
  row_number()over(partition by s_name order by MARK_VALUE desc) rn
 from table_name
) t where t.rn=1

或者你可以使用关联子查询

select t1.* from table_name t1
  where t.MARK_VALUE=(select max(MARK_VALUE) from table_name t2 where t2.S_NAME=t1.S_NAME)

【讨论】:

【参考方案5】:

使用row_number()

select * from
(
select *,row_number() over(partition by s_name order by MARK_VALUE desc) as rn
 from tablename
)A where rn=1

【讨论】:

以上是关于SQL查询:返回组的最大值记录的主要内容,如果未能解决你的问题,请参考以下文章

每个组的本地最大值的 SQL 排序结果

选择所有唯一元组的 SQL 查询

sql 子查询返回的值不止一个怎么解决?

SQL查询返回具有特定ID的所有项目[关闭]

SQL 查询 - 分组并计算最大值 - 最小值

SQL 如何返回最大值所在的多条记录