выберите максимальный балл, сгруппированный по дате, отобразите полную дату и время
-
12-09-2019 - |
Вопрос
Добрый день, у меня есть таблица, которая показывает серию результатов и даты, когда эти результаты были получены.Я бы хотел выбрать максимальное количество этих баллов за каждый день, но отобразить дату и время, когда этот балл был получен.
Я использую базу данных Oracle (10g), и таблица структурирована следующим образом:
scoredatetime score (integer) --------------------------------------- 01-jan-09 00:10:00 10 01-jan-09 01:00:00 11 01-jan-09 04:00:01 9 ...
Я хотел бы иметь возможность представить результаты таким образом, чтобы вышеприведенное стало:
01-jan-09 01:00:00 11
Этот следующий запрос подводит меня к цели на полпути..но не до конца.
select
trunc(t.scoredatetime), max(t.score)
from
mytable t
group by
trunc(t.scoredatetime)
Я не могу присоединиться по количеству баллов только потому, что один и тот же высокий балл мог быть достигнут несколько раз в течение дня.
Я ценю вашу помощь!
Саймон Эдвардс
Решение
with mytableRanked(d,scoredatetime,score,rk) as (
select
scoredatetime,
score,
row_number() over (
partition by trunc(scoredatetime)
order by score desc, scoredatetime desc
)
from mytable
)
select
scoredatetime,
score
from mytableRanked
where rk = 1
order by date desc
В случае нескольких высоких результатов в течение дня возвращается строка, соответствующая той, которая была набрана последней в течение дня.Если вы хотите увидеть все наивысшие баллы за день, удалите scoredatetime desc из спецификации order by в окне row_number.
В качестве альтернативы, вы можете сделать это (в нем будут перечислены связи, набравшие наибольшее количество баллов за дату).:
select
scoredatetime,
score
from mytable
where not exists (
select *
from mytable as M2
where trunc(M2.scoredatetime) = trunc(mytable.scoredatetime)
and M2.score > mytable.scoredatetime
)
order by scoredatetime desc
Другие советы
Прежде всего, вы еще не указали, что должно произойти, если две или более строк в течение одного дня содержат одинаковый высокий балл.
Два возможных ответа на этот вопрос:
1) Просто выберите одно из значений scoredatetime, не имеет значения, какое именно
В этом случае не используйте самосоединения или аналитику, как вы видите в других ответах, потому что существует специальная агрегирующая функция, которая может сделать вашу работу более эффективной.Пример:
SQL> create table mytable (scoredatetime,score)
2 as
3 select to_date('01-jan-2009 00:10:00','dd-mon-yyyy hh24:mi:ss'), 10 from dual union all
4 select to_date('01-jan-2009 01:00:00','dd-mon-yyyy hh24:mi:ss'), 11 from dual union all
5 select to_date('01-jan-2009 04:00:00','dd-mon-yyyy hh24:mi:ss'), 9 from dual union all
6 select to_date('02-jan-2009 00:10:00','dd-mon-yyyy hh24:mi:ss'), 1 from dual union all
7 select to_date('02-jan-2009 01:00:00','dd-mon-yyyy hh24:mi:ss'), 1 from dual union all
8 select to_date('02-jan-2009 04:00:00','dd-mon-yyyy hh24:mi:ss'), 0 from dual
9 /
Table created.
SQL> select max(scoredatetime) keep (dense_rank last order by score) scoredatetime
2 , max(score)
3 from mytable
4 group by trunc(scoredatetime,'dd')
5 /
SCOREDATETIME MAX(SCORE)
------------------- ----------
01-01-2009 01:00:00 11
02-01-2009 01:00:00 1
2 rows selected.
2) Выберите все записи с максимальным количеством баллов.
В этом случае вам нужна аналитика с функцией RANK или DENSE_RANK.Пример:
SQL> select scoredatetime
2 , score
3 from ( select scoredatetime
4 , score
5 , rank() over (partition by trunc(scoredatetime,'dd') order by score desc) rnk
6 from mytable
7 )
8 where rnk = 1
9 /
SCOREDATETIME SCORE
------------------- ----------
01-01-2009 01:00:00 11
02-01-2009 00:10:00 1
02-01-2009 01:00:00 1
3 rows selected.
С уважением, Роб.
Для выполнения этого вам могут понадобиться два оператора SELECT:первый для сбора усеченной даты и связанного с ней максимального балла, а второй для извлечения фактических значений даты и времени, связанных с баллом.
Попробуй:
SELECT T.ScoreDateTime, T.Score
FROM
(
SELECT
TRUNC(T.ScoreDateTime) ScoreDate, MAX(T.score) BestScore
FROM
MyTable T
GROUP BY
TRUNC(T.ScoreDateTime)
) ByDate
INNER JOIN MyTable T
ON TRUNC(T.ScoreDateTime) = ByDate.ScoreDate and T.Score = ByDate.BestScore
ORDER BY T.ScoreDateTime DESC
Это также приведет к ничьей с лучшим результатом.
Для версии, которая выбирает только самый последний опубликованный рекорд за каждый день:
SELECT T.ScoreDateTime, T.Score
FROM
(
SELECT
TRUNC(T.ScoreDateTime) ScoreDate,
MAX(T.score) BestScore,
MAX(T.ScoreDateTime) BestScoreTime
FROM
MyTable T
GROUP BY
TRUNC(T.ScoreDateTime)
) ByDate
INNER JOIN MyTable T
ON T.ScoreDateTime = ByDate.BestScoreTime and T.Score = ByDate.BestScore
ORDER BY T.ScoreDateTime DESC
Это может привести к появлению нескольких записей за дату, если две разные оценки были опубликованы в одно и то же время.