Oracle оптимизирует SQL-запрос - Multiple Max () - PullRequest
2 голосов
/ 23 сентября 2019

У меня есть таблица, где сначала мне нужно выбрать данные по max(event_date), затем нужно отфильтровать данные по max(event_sequence), а затем снова фильтровать по max(event_number)

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

Здесь запрос

SELECT DISTINCT a.stuid,
                   a.prog,
                   a.stu_prog_id,
                   a.event_number,
                   a.event_date,
                   a.event_sequence,
                   a.prog_status
   FROM table1 a
   WHERE a.event_date=
       (SELECT max(b.event_date)
        FROM table1 b
        WHERE a.stuid=b.stuid
          AND a.prog=b.prog
          AND a.stu_prog_id=b.stu_prog_id)
     AND a.event_seq=
       (SELECT max(b.event_sequence)
        FROM table1 b
        WHERE a.stuid=b.stuid
          AND a.prog=b.prog
          AND a.stu_prog_id=b.stu_prog_id
          AND a.event_date=b.event_date)
     AND a.event_number=
       (SELECT max(b.event_number)
        FROM table1 b
        WHERE a.stuid=b.stuid
          AND a.prog=b.prog
          AND a.stu_prog_id=b.stu_prog_id
          AND a.event_date=b.event_date
          AND a.event_sequence=b.event_sequence

Мне было интересно, есть ли более быстрый способ получить данные?Я использую Oracle 12c.

Ответы [ 4 ]

2 голосов
/ 23 сентября 2019

Вы можете попробовать перефразировать ваш запрос, используя аналитические функции:

SELECT
    stuid,
    prog,
    stu_prog_id,
    event_number,
    event_date,
    event_sequence,
    prog_status
FROM
(
    SELECT t.*,
        RANK() OVER (PARTITION BY studio, prog, stu_prog_id
                     ORDER BY event_date DESC) rnk1,
        RANK() OVER (PARTITION BY studio, prog, stu_prog_id, event_date
                     ORDER BY event_sequence DESC) rnk2,
        RANK() OVER (PARTITION BY studio, prog, stu_prog_id, event_date, event_sequence
                     ORDER BY event_number DESC) rnk3
    FROM table1 t
) t
WHERE rnk1 = 1 AND rnk2 = 1 AND rnk3 = 1;

Примечание. На самом деле я не знаю, действительно ли вам нужны все три подзапроса.Добавление примеров данных к вашему вопросу может помочь кому-то еще улучшить решение, которое я дал выше.

0 голосов
/ 23 сентября 2019

Я думаю, вы хотите просто row_number() или rank():

select t1.*
from (select t1.*,
             rank() over (partition by stuid, prog, stu_prog_id
                          order by event_date desc, event_sequence desc, event_number desc
                         ) as seqnum
      from table1 t1
     ) t1
where seqnum = 1;
0 голосов
/ 23 сентября 2019

Если у вас есть несколько записей с максимальным значением EVENT_DATE, EVENT_SEQUENCE, EVENT_NUMBER, то в решении Тима используйте DENSE_RANK или используйте следующее, чтобы получить exact max и сравнить с original column data.

SELECT DISTINCT
    A.STUID,
    A.PROG,
    A.STU_PROG_ID,
    A.EVENT_NUMBER,
    A.EVENT_DATE,
    A.EVENT_SEQUENCE,
    A.PROG_STATUS
FROM
    (
        SELECT
            A.STUID,
            A.PROG,
            A.STU_PROG_ID,
            A.EVENT_NUMBER,
            A.EVENT_DATE,
            A.EVENT_SEQUENCE,
            A.PROG_STATUS,
            MAX(A.EVENT_DATE) OVER(
                PARTITION BY A.STUID, A.PROG, A.STU_PROG_ID
            ) AS MAX_EVENT_DATE,
            MAX(A.EVENT_SEQUENCE) OVER(
                PARTITION BY A.STUID, A.PROG, A.STU_PROG_ID, A.EVENT_DATE
            ) AS MAX_EVENT_SEQUENCE,
            MAX(A.EVENT_NUMBER) OVER(
                PARTITION BY A.STUID, A.PROG, A.STU_PROG_ID, A.EVENT_DATE, A.EVENT_SEQUENCE
            ) AS MAX_EVENT_NUMBER
        FROM
            TABLE1 A
    ) A
WHERE
    A.MAX_EVENT_DATE = A.EVENT_DATE
    AND A.MAX_EVENT_SEQUENCE = A.EVENT_SEQUENCE
    AND A.MAX_EVENT_NUMBER = A.EVENT_NUMBER;

Ура !!

0 голосов
/ 23 сентября 2019

Являясь пользователем Oracle 12c, вы можете использовать синтаксис

[ OFFSET offset { ROW | ROWS } ]
[ FETCH { FIRST | NEXT } [ { rowcount | percent PERCENT } ]
    { ROW | ROWS } { ONLY | WITH TIES } ]

в виде:

SELECT DISTINCT a.stuid,
                a.prog,
                a.stu_prog_id,
                a.event_number,
                a.event_date,
                a.event_sequence,
                a.prog_status
  FROM table1 a
 ORDER BY event_date DESC, event_sequence DESC, event_number DESC
 FETCH FIRST 1 ROW ONLY;

, где в вашем случае не требуется выражение WITH TIES, поскольку вы 'выполняется поиск DISTINCT строк, и OFFSET также не требуется, поскольку начальная точка - это только начало упорядоченных по убыванию столбцов.Даже использование ключевого слова ROW в качестве ROWS является необязательным, даже в случае множественных строк, таких как FETCH FIRST 5 ROW ONLY; ^^ --> ROWS without S

Демо

...