Среднее за последние 30 дней, не включая текущую запись (смешанная дата и условие на основе строк) - PullRequest
0 голосов
/ 25 июня 2019

Я работаю над столбцом с именем CRD_TRX_SYAMT_AVG_30d, который удовлетворяет следующим критериям:

  • Вычисляет среднее значение столбца SYSTEMAMOUNT за последние 30 дней в соответствии с TRXHOSTDATETIME
  • Исключая строки, где RESPONSECODE не равно 00
  • Без учета текущей записи

Ниже приведены полные образцы данных. И я вставил это в БД Fiddle, но есть проблема, препятствующая запуску кода там. Для меня это нормально работает в SQL Developer, но дает неожиданные результаты.

Я пытался заменить CURRENT ROW на 1 PRECEDING, но я не могу смешать интервал и диапазон, насколько я понимаю. Столбец CRD_TRX_SYAMT_AVG_30_trx_exc использует условие на основе строк (строки между 30 PRECEDING и 1 PRECEDING), и это прекрасно работает. Так что проблема только с CRD_TRX_SYAMT_AVG_30d.

Как я могу изменить условие на что-то вроде следующего?

RANGE BETWEEN INTERVAL '30' DAY PRECEDING AND 1 PRECEDING

https://dbfiddle.uk/?rdbms=oracle_18&fiddle=471da47ef5df960b67e427053e7642d4

-- DATE formatting
alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';

-- DROP and CREATE TABLE
DROP TABLE TMP_EXA_RSS_ISS_AUT_S_100CRD_T;

CREATE TABLE "RAI"."TMP_EXA_RSS_ISS_AUT_S_100CRD_T" 
 (  "ID_KEY_HASH" VARCHAR2(10), 
"TRXHOSTDATETIME" DATE, 
"SYSTEMAMOUNT" NUMBER(10,1), 
"RESPONSECODE" CHAR(2)
 );

 -- fill entire table
DECLARE
  nTRX NUMBER(10) := 100;
BEGIN
FOR i IN 1 .. nTRX LOOP
  INSERT INTO tmp_exa_RSS_ISS_AUT_S_100CRD_T VALUES
  (
    FLOOR(DBMS_RANDOM.VALUE (1, 4)), -- ID_KEY_HASH
    TO_DATE('01.01.2018', 'DD.MM.YYYY') + dbms_random.value(0, 60), -- TRXHOSTDATETIME
    FLOOR(DBMS_RANDOM.VALUE (1, 10)) * 100, -- SYSTEMAMOUNT
    CASE round(dbms_random.value(1,11)) 
            WHEN 1 THEN '55' 
            WHEN 2 THEN '88'
            ELSE '00'
       END -- RESPONSECODE 
  );
END LOOP;
END;
/

-- review all data created
SELECT * FROM tmp_exa_RSS_ISS_AUT_S_100CRD_T ORDER BY ID_KEY_HASH, TRXHOSTDATETIME;


-- example features:

SELECT ID_KEY_HASH, TRXHOSTDATETIME, SYSTEMAMOUNT, RESPONSECODE,
ROUND(AVG(
  CASE WHEN ((SYSTEMAMOUNT > 0) AND (RESPONSECODE = '00')  ) THEN SYSTEMAMOUNT ELSE NULL END
) OVER (PARTITION BY ID_KEY_HASH ORDER BY TRXHOSTDATETIME 
                        RANGE BETWEEN INTERVAL '30' DAY PRECEDING AND CURRENT ROW), 2)  AS CRD_TRX_SYAMT_AVG_30d,
NVL( ROUND( 
  AVG(
      CASE WHEN ((SYSTEMAMOUNT > 0) AND (RESPONSECODE = '00')  ) THEN SYSTEMAMOUNT ELSE NULL END
      ) 
      OVER (PARTITION BY ID_KEY_HASH ORDER BY TRXHOSTDATETIME NULLS LAST 
      ROWS BETWEEN 30 PRECEDING AND 1 PRECEDING)
  , 2), 0 ) AS CRD_TRX_SYAMT_AVG_30_trx_exc
FROM tmp_exa_RSS_ISS_AUT_S_100CRD_T
ORDER BY ID_KEY_HASH, TRXHOSTDATETIME
;

1 Ответ

3 голосов
/ 25 июня 2019

Если составной (ID_KEY_HASH, TRXHOSTDATETIME) является уникальным (без одинаковых дат и времени для того же ID_KEY_HASH), то следующее выражение сделает то, что вам нужно:

 avg(case when systemamount > 0 and responsecode = '00' then systemamount end)
   over (partition by id_key_hash order by TRXHOSTDATETIME 
         range between interval '30' day preceding 
                   and interval '1' second preceding)

При необходимости вы можете обернуть его в ROUND( ... , 2).

...