SQL-запрос: возвращает запись о максимальном значении группы - PullRequest
0 голосов
/ 12 марта 2019

У меня есть образец таблицы с аналогичной структурой и данными, как показано ниже:

+------+---------+-------------+------------+
| 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 |
+------+---------+-------------+------------+

Ответы [ 5 ]

1 голос
/ 12 марта 2019

используйте 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)
1 голос
/ 12 марта 2019

Аналитическая функция 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>
0 голосов
/ 12 марта 2019

Вы можете использовать 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() для функций агрегирования. По моему опыту, это довольно быстро.

0 голосов
/ 12 марта 2019

Пожалуйста, попробуйте это.

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 голосов
/ 12 марта 2019

Использование 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
...