使用分析函数优化或简化复杂的SELECT

时间:2017-03-23 00:01:55

标签: oracle plsql

鉴于表STATEMENT(下面提供的创建和数据插入命令)中的以下数据,我希望提取字段CUMULATEDAMOUNT的值,以获取STATEMENTNUMBER的最大值,该最大值对应于STATEMENTDATETIME的最大值,用于记录组与ACCOUNTKEY值相同的ACCOUNTKEY值,其中RUNID = 14547。

SQL> select * from statement order by 2,4;


    +------------+----------+---------------+------------------+----------------+------+-----------------+----------+
    |STATEMENTKEY|ACCOUNTKEY|CLASSIFICATION | STATEMENTDATETIME|STATEMENTNUMBER |RUNID |CUMULATEDAMOUNT  |STATUS    |
    +------------+----------+---------------+------------------+----------------+------+-----------------+----------+
    |      111177|    888881|EndOfDay       | 27/11/15         | 199            |14306 |         202,12  |Created   |
    |      111177|    888881|EndOfDay       | 27/11/15         | 192            |14302 |         606,66  |Processed |
    |      111155|    888882|EndOfDay       | 30/11/15         | 301            |14552 |         303,33  |Processed |
    |      111127|    888886|IncIday        | 27/11/15         | 198            |14506 |         707,77  |Processed |
    |      111118|    888888|EndOfDay       | 17/11/15         | 119            |14547 |         808,88  |Processed |
    |      111112|    888888|EndOfDay       | 19/11/15         | 103            |14500 |         909,99  |Processed |
    |      111144|    888888|EndOfDay       | 27/11/15         | 204            |14509 |         505,55  |Processed |
    |      111183|    888888|EndOfDay       | 28/11/15         | 202            |14514 |         404,44  |Processed |
    |      111104|    888888|EndOfDay       | 29/11/15         | 201            |14513 |         101,11  |Processed |
    |      111194|    888888|EndOfDay       | 29/11/15         | 239            |14813 |         102,22  |Processed |
    +------------+----------+---------------+------------------+----------------+------+-----------------+----------+
    10 ligne(s) selectionnee(s).

因此,对于RUNID = 14547,ACCOUNTKEY = 888888,这会产生6条记录

SQL> select * from statement where ACCOUNTKEY = 888888 order by 2,4;

    +------------+----------+-----------------+--------------------+-------------------+------+---------------+---------+
    |STATEMENTKEY|ACCOUNTKEY| CLASSIFICATION  |  STATEMENTDATETIME |  STATEMENTNUMBER  | RUNID|CUMULATEDAMOUNT|STATUS   |
    |------------|----------|-----------------|--------------------|-------------------+------+---------------+---------|
    |      111118|    888888| EndOfDay        |  17/11/15          |  119              | 14547| 808,88        |Processed|
    |      111112|    888888| EndOfDay        |  27/11/15          |  103              | 14500| 909,99        |Processed|
    |      111144|    888888| EndOfDay        |  28/11/15          |  204              | 14509| 505,55        |Processed|
    |      111183|    888888| EndOfDay        |  29/11/15          |  202              | 14514| 404,44        |Processed|
    |      111104|    888888| EndOfDay        |  29/11/15          |  201              | 14513| 101,11        |Processed|
    |      111194|    888888| EndOfDay        |  29/11/15          |  239              | 14813| 102,22        |Processed| 
    +------------+----------+-----------------+--------------------+-------------------+------+---------------+---------+
    6 ligne(s) selectionnee(s).

MAX(STATEMENTDATETIME)= 29/11/15,其中MAX(STATEMENTNUMBER)= 239,给出了所需的结果:CUMULATEDAMOUNT = 102,22

我目前的选择如下:

 select cumulatedamount from statement STX WHERE STX.statementKey in (
    SELECT distinct st2.statementKey FROM statement st2
    INNER JOIN
    (
        SELECT S2.ACCOUNTKEY           as ACCOUNTKEY,
               S2.CLASSIFICATION       as CLASSIFICATION,
               S2.STATEMENTDATETIME    as STATEMENTDATETIME,
               MAX(S2.STATEMENTNUMBER) as STATEMENTNUMBER
        FROM
        (
          SELECT ACCOUNTKEY,
                 CLASSIFICATION,
                 MAX(STATEMENTDATETIME) AS STATEMENTDATETIME
          FROM STATEMENT st3
          WHERE
            STATUS in ('Processed', 'Created')
          AND EXISTS
          (
            SELECT stCur.statementKey FROM statement stCur
            WHERE stCur.runId=14547
            AND stCur.accountKey = st3.accountKey
          )
          GROUP BY
              ACCOUNTKEY, CLASSIFICATION
        ) S1
        INNER JOIN STATEMENT S2 ON S2.ACCOUNTKEY = S1.ACCOUNTKEY
        AND
            S2.STATEMENTDATETIME=S1.STATEMENTDATETIME
        AND
            S2.STATUS in ('Processed', 'Created')
        AND
          S1.CLASSIFICATION =S2.CLASSIFICATION
        GROUP BY S2.ACCOUNTKEY,S2.CLASSIFICATION,S2.STATEMENTDATETIME
    ) v
    ON
    (
        st2.accountKey = v.accountKey
      and
        st2.classification = v.classification
      and
        st2.STATEMENTDATETIME=v.STATEMENTDATETIME
      and
        st2.STATEMENTNUMBER=v.STATEMENTNUMBER
      and
        st2.status in ('Processed', 'Created')
    )
    WHERE
        st2.accountKey = STX.accountKey
    AND
        st2.classification = STX.classification ) AND STX.classification in ('EndOfDay','IncIday'); 

创建表格:

CREATE TABLE STATEMENT
(
 STATEMENTLEY NUMBER(38) NOT NULL,
 ACCOUNTKEY  NUMBER(38),
 CLASSIFICATION VARCHAR2(30),
 STATEMENTDATETIME DATE NOT NULL ,
 STATEMENTNUMBER VARCHAR2(35),
 RUNID NUMBER(38),
 CUMULATEDAMOUNT NUMBER(38,5),
 STATUS VARCHAR2(30)
);

插入数据:

insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111104,888888,'EndOfDay',to_date('29-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),201,14513,101.11,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111194,888888,'EndOfDay',to_date('29-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),239,14813,102.22,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111177,888881,'EndOfDay',to_date('27-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),199,14306,202.12,'Created');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111155,888882,'EndOfDay',to_date('30-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),301,14552,303.33,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111183,888888,'EndOfDay',to_date('28-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),202,14514,404.44,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111144,888888,'EndOfDay',to_date('27-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),204,14509,505.55,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111177,888881,'EndOfDay',to_date('27-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),192,14302,606.66,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111127,888886,'IncIday',to_date('27-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),198,14506,707.77,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111118,888888,'EndOfDay',to_date('17-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),119,14547,808.88,'Processed');
insert into statement (statementkey,accountkey,classification,statementdatetime,statementnumber,runid,cumulatedamount,status)values (111112,888888,'EndOfDay',to_date('19-11-2015 11:00:00','DD-MM-YYYY HH24:MI:SS'),103,14500,909.99,'Processed');
commit;

我想通过使用分析函数简化上面的SELECT,非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

SELECT *
  FROM (SELECT *
         FROM STATEMENT
         WHERE ACCOUNTKEY = (SELECT ACCOUNTKEY FROM STATEMENT WHERE RUNID = 14547)
         ORDER BY STATEMENTDATETIME DESC,  STATEMENTNUMBER DESC
       )
   WHERE ROWNUM = 1

或使用分析函数而不是rownum:

SELECT *
  FROM (SELECT s.*
              ,row_number() OVER(ORDER BY STATEMENTDATETIME DESC, STATEMENTNUMBER DESC) rn
         FROM STATEMENT s
         WHERE ACCOUNTKEY = (SELECT ACCOUNTKEY FROM STATEMENT WHERE RUNID = 14547)
       )
   WHERE rn = 1 

*替换为CUMULATEDAMOUNT

并相应地添加其他过滤条件STATUS in ('Processed', 'Created') ...

答案 1 :(得分:1)

请使用RANK() OVER (PARTITION BY .. ORDER BY ..)

低于一个
SELECT CUMULATEDAMOUNT
FROM (
  SELECT CUMULATEDAMOUNT
    , RANK() OVER (ORDER BY STATEMENTDATETIME DESC, STATEMENTNUMBER DESC) RNK
  FROM (
    SELECT * 
    FROM STATEMENT
    WHERE ACCOUNTKEY IN (
        SELECT ACCOUNTKEY 
          FROM STATEMENT
        WHERE RUNID = 14547
      )
  )
) WHERE RNK = 1