I have a sample table with similar structure & data as shown below:
+------+---------+-------------+------------+
| S_ID | S_NAME | SUBJECT | MARK_V
Analytic function ROW_NUMBER can be used to group rows by S_NAME (as you want to get maximum mark per student), and sort marks in descending order so that the max value raises to the top (i.e. gets row number = 1).
Then select rows with that row number value.
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>
if your database version doesn't support analytic functions, there's another option which isn't that good as it selects from the same table twice. You won't notice the difference if there aren't that many rows in a table, but performance will suffer on large data sets.
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>