你这题咋说没人解得开呢?
首先你没指定oracle的版本,我用21c版本写了个
with t ( cust_id, dt , prd_id, amt, type) as (
select 'A123', date'2022-01-01', 'aa11', 1000001, 'buy' from dual union all
select 'A123', date'2022-01-05', 'aa11', 1000000, 'sell' from dual union all
select 'B123', date'2022-01-06', 'bb22', 1000, 'buy' from dual union all
select 'B123', date'2022-01-07', 'bb22', 1000, 'sell' from dual union all
select 'C123', date'2022-01-08', 'aa11', 2000000, 'buy' from dual union all
select 'D123', date'2022-01-09', 'aa11', 2000000, 'buy' from dual union all
select 'D123', date'2022-03-09', 'aa11', 2000000, 'sell' from dual union all
select 'D123', date'2022-03-10', 'aa11', 2000000, 'sell' from dual)
, t1 as (
select t.*,
bit_and_agg(case when type='sell' THEN 1 ELSE 0 END) over w1 as ct ,
sum(amt) over w1 as sum_amt
from t
window w1 as(partition by cust_id order by dt range between 30 preceding and current row)
)
select * from t where exists
(select 1 from t1 where ct=0 and sum_amt>2000000
and t.cust_id=t1.cust_id and t.dt between t1.dt-30 and t1.dt)

t表是模拟数据,
t1的目的是增加两个列,即往前数30天是否存在多个类型,以及往前数30天求和,
低版本的oracle中,window 窗口需要放上去,这个可以改,
bit_and_agg这个函数是21c版本新增的,是按位与聚合运算,即只要有2个不同的值则返回0,主要原因是移动窗口不能用count(distinct),当然低版本可以用其他方法,只是sql又变长了
还是写个低版本的处理方法吧
with t ( cust_id, dt , prd_id, amt, type) as (
select 'A123', date'2022-01-01', 'aa11', 1000001, 'buy' from dual union all
select 'A123', date'2022-01-05', 'aa11', 1000000, 'sell' from dual union all
select 'B123', date'2022-01-06', 'bb22', 1000, 'buy' from dual union all
select 'B123', date'2022-01-07', 'bb22', 1000, 'sell' from dual union all
select 'C123', date'2022-01-08', 'aa11', 2000000, 'buy' from dual union all
select 'D123', date'2022-01-09', 'aa11', 2000000, 'buy' from dual union all
select 'D123', date'2022-03-09', 'aa11', 2000000, 'sell' from dual union all
select 'D123', date'2022-03-10', 'aa11', 2000000, 'sell' from dual)
, t1 as (
select t.*,
trunc(EXP(SUM(LN(case when type='sell' THEN 2 ELSE 3 END))
over (partition by cust_id order by dt range between 30 preceding and current row))) as ct ,
sum(amt)
over (partition by cust_id order by dt range between 30 preceding and current row) as sum_amt
from t
)
select * from t where exists
(select 1 from t1 where mod(ct,6)=0 and sum_amt>2000000
and t.cust_id=t1.cust_id and t.dt between t1.dt-30 and t1.dt)

这个sql在11g/12c/18c/19c/21c均测试通过。
主要和上面那个版本的区别,除了把窗口定义放上去了,更重要的一点是,将要做去重统计的两个值转换成两个质数,然后计算一列的乘积,如果最后这个乘积满足除以两个质数之积余0,那么说明它的因数肯定同时含有这两个质数,即同时含有多个值