выберите максимальную оценку, сгруппированную по дате, отобразите полную дату и время - PullRequest
1 голос
/ 21 сентября 2009

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

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

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

Я ценю вашу помощь!

Саймон Эдвардс

Ответы [ 3 ]

3 голосов
/ 21 сентября 2009
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 из заказа по спецификации в окне 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 голос
/ 21 сентября 2009

Прежде всего, вы еще не указали, что должно произойти, если две или более строки в один и тот же день содержат одинаковый высокий балл.

Два возможных ответа на этот вопрос:

1) Просто выберите одно из забитых времен, не имеет значения, какое из них

В этом случае не используйте самостоятельные объединения или аналитику, как вы видите в других ответах, потому что есть специальная агрегатная функция, которая может сделать вашу работу более эффективной. Пример:

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.

С уважением, Роб.

0 голосов
/ 21 сентября 2009

Для этого вам могут понадобиться два оператора 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

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

...