Oracle 优化 SQL 查询 - 多个 Max()

Oracle optimise SQL query - Multiple Max()

我有一个 table,首先我需要 select 数据 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。

您可以尝试使用分析函数重新表述您的查询:

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;

注意:我实际上不知道您是否真的需要那里的所有三个子查询。将样本数据添加到您的问题可能会帮助其他人改进我上面给出的解决方案。

作为 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

Demo

如果您有多个记录分别以 EVENT_DATE, EVENT_SEQUENCE, EVENT_NUMBER 作为最大值,那么在 Tim 的解决方案中,使用 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;

干杯!!

我想你想要一个简单的 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;