2

私は 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 よりも大きい 2 つの日付 (月の最初の日と最後の日を含む) の間に発生したすべての小切手トランザクションを返すことです (次の式を使用します)。この場合は 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 は、結合の選択内に表示されることはありません。

誰か賢いアイデアを持っている人はいますか?

4

1 に答える 1