выберите максимальный балл, сгруппированный по дате, отобразите полную дату и время

StackOverflow https://stackoverflow.com/questions/1452839

Вопрос

Добрый день, у меня есть таблица, которая показывает серию результатов и даты, когда эти результаты были получены.Я бы хотел выбрать максимальное количество этих баллов за каждый день, но отобразить дату и время, когда этот балл был получен.

Я использую базу данных 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

Это может привести к появлению нескольких записей за дату, если две разные оценки были опубликованы в одно и то же время.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top