我有一个类似结构和数据的示例表,如下所示:
+------+---------+-------------+------------+
| 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 |
+------+---------+-------------+------------+
表格中列出了每个学生出现的所有科目中每个学生的合并标记。
请帮助我,写一个查询来提取每个学生获得的MAXIMUM标记(不论学科/其他学生),如下:
按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 |
+------+---------+-------------+------------+
使用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)
分析函数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>
使用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
请试试这个。
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
你可以使用group by
和keep
:
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()
等功能进行聚合功能。根据我的经验,这是非常快的。