SQL Query: Return Max value record of a Group

前端 未结 5 1554
庸人自扰
庸人自扰 2020-12-04 03:48

I have a sample table with similar structure & data as shown below:

+------+---------+-------------+------------+
| S_ID | S_NAME  | SUBJECT     | MARK_V         


        
相关标签:
5条回答
  • 2020-12-04 04:23

    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.

     <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>
    
    0 讨论(0)
  • 2020-12-04 04:33

    use row_number() window function

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

    or you can use corelated subquery

    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)
    
    0 讨论(0)
  • 2020-12-04 04:35

    You can use group by and 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 is an Oracle extension that allows functionality like first_value() and last_value() for aggregation functions. In my experience, it is quite fast.

    0 讨论(0)
  • 2020-12-04 04:37

    Use 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
    
    0 讨论(0)
  • 2020-12-04 04:43

    Please try this.

    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
    
    0 讨论(0)
提交回复
热议问题