过去 30 天的平均值,不包括当前记录(混合日期和基于行的条件)
Posted
技术标签:
【中文标题】过去 30 天的平均值,不包括当前记录(混合日期和基于行的条件)【英文标题】:Average over last 30 days not including current record (mixed date and row-based condition) 【发布时间】:2019-06-25 15:16:30 【问题描述】:我正在编写一个名为 CRD_TRX_SYAMT_AVG_30d
的专栏,该专栏符合以下条件:
TRXHOSTDATETIME
计算过去30天SYSTEMAMOUNT
列的平均值
排除 RESPONSECODE
不是 00 的行
排除当前记录
下面有完整的示例数据。我已经将它粘贴到 DB Fiddle 中,但是有一个问题阻止代码在那里运行。对我来说,它在 SQL Developer 中运行良好,但结果出乎意料。
我尝试用 1 个 PRECEDING 代替 CURRENT ROW,但根据我的理解,不可能混合使用间隔和范围。 CRD_TRX_SYAMT_AVG_30_trx_exc
列使用基于行的条件(ROWS BETWEEN 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
;
【问题讨论】:
向我们展示数据库架构、示例数据、当前和预期输出。请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。 How to create a Minimal, Complete, and Verifiable example 尝试在rextester.com 中创建样本 而不是 FOR .. LOOP 只使用 INSERT,但给我们一个工作示例,否则我们无法测试它 我已经为你修好了小提琴:dbfiddle.uk/… 但我认为这个小提琴不适合测试一个像这样的 hudreds 行的大型演示,因为它只显示最大。 10 行。 使用随机值的问题是我们不知道结果应该是什么;如果您提供了固定插入,那么您可以包括您的预期结果,并有一些更具体的目标和测试。你可能只想要RANGE BETWEEN 30 PRECEDING AND 1 PRECEDING
,但目前很难说。
怎么样:range between interval '30' day preceding and interval '1' second preceding
?只要您不能为同一 ID_KEY_HASH
重复日期时间,这应该可以工作。
【参考方案1】:
如果复合 (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)
中。
【讨论】:
我认为这个假设适用于我的用例。我将您的解决方案放在 DB Fiddle 上:dbfiddle.uk/…。我不知道为什么,但是随机数生成器的种子不起作用。以上是关于过去 30 天的平均值,不包括当前记录(混合日期和基于行的条件)的主要内容,如果未能解决你的问题,请参考以下文章