我正在与 SQR 合作编写一份报告。我无法改变数据库的结构,也无法使用 PL/SQL 来完成这项任务。
由于报告可以从远程位置运行,我不想从 SQR 中多次调用数据库。我的目标是在 1 个 SQL 中返回所有内容,其中仅包含我需要报告的记录,以增加慢速连接的运行时间。
我现在可以使用它,但我担心数据库的性能。
“事务”表具有可用于此目的的以下字段:
account_num number(10) -- the account number
seq_num number(10) -- not a real sequence, it is unique to account_num
check_num number(10) -- the number on the check
postdate date
主键是 (account_num, seq_num)
示例数据如下所示:
account_num seq_num check_num postdate
----------- ---------- ---------- ----------
1 11 200 2014-07-13
1 16 201 2014-07-14
1 23 205 2014-07-15
2 52 282 2014-07-13
2 66 284 2014-07-14
2 72 231 2014-07-15
3 11 201 2014-07-13
3 12 202 2014-07-14
3 15 203 2014-07-15
注意:表中还有许多其他类型的交易,但我们正在过滤交易类型的列表,这对这个问题不是很重要,所以我把它省略了。交易量似乎平均每月约为 750,000 笔(针对所有交易,而不仅仅是支票),其中平均报告了约 10,000 笔支票交易。
选择标准是返回发生在两个日期(包括 - 通常是一个月的第一天和一个月的最后一天)之间发生的所有支票交易,其中帐户的任何排序支票号码之间的差异大于 X(我们将使用10 在这种情况下)。
使用上面的示例数据,结果如下所示:
account_num seq_num check_num postdate
----------- ---------- ---------- ----------
2 52 282 2014-07-13
2 66 284 2014-07-14
2 72 231 2014-07-15
由于 check_num 282 和 231 之间的差值大于 10,所以返回 account_num 2 的所有支票。
我构建了以下 SQL 来返回上面的结果:
select
t1.*
from
transactions t1
join (
select
t3.account_num,
t3.min_postdate,
t3.max_postdate,
max(t3.check_diff)
from (
select distinct
t4.account_num,
lead(t4.check_num, 1, t4.check_num) over (partition by t4.account_num order by t4.check_num) - t4.check_num as check_diff,
min(t4.postdate) over (partition by t4.account_num) min_postdate,
max(t4.postdate) over (partition by t4.account_num) max_postdate
from
transactions t4
where
t4.postdate between trunc(sysdate,'mm') and last_day(trunc(sysdate))) t3
group by
t3.account_num,
t3.min_postdate,
t3.max_postdate
having max(t3.check_diff) > 10) t2
on t1.account_num = t2.account_num
and t1.postdate between t2.min_postdate and t2.max_postdate
;
我想从 t4 返回所有检查的 seq_num,所以我最终使用 t1 上的主键。我尝试过使用 LISTAGG,它可以将数字放在一起。
listagg(t4.seq_num,',') within group (order by seq_num) over (partition by account_num) sqe_nums
但这是我卡住的地方......使用逗号分隔的字符串。我可以使用 INSTR 让它工作,但它不能使用主键并且性能很糟糕。
instr(t1.seq_num || ',', t2.seq_nbrs || ',') > 0
我试着加入它:
join (
select
t2.account_num,
regexp_substr(t2.seq_nums,'[^,]+{1}',1,level) seq_num
from
dual
connect by
level <= length(regexp_replace(t2.seq_nums,'[^,]*')) + 1) t5
on t1.account_num = t5. accout_num
and t1.sqe_num = t5.seq_num
但我应该更清楚 (ORA-00904) - t2 在连接的选择中永远不可见。
有没有人有任何聪明的想法?