2017-04-11 4 views
1

私は2つのテーブルを持っています: 1)それらの1つは請求書用であり、何千ものデータがあります。私のINVOICESテーブルには、顧客に対する請求書とその価格があります。 2)もう1つは債務です。私のDEBTSテーブルには、すべての顧客に対する請求書の債務総額があります。
私の目標は、最も近い金額と債務の請求書を見つけることです。オラクルで最も近いサブセットの合計を見つける方法

DEBTSテーブル:

CUSTOMER_ID   TOTAL_DEBTS 
     3326660    444$  
     2789514    165$  
     4931541    121$ 

INVOICESテーブル:

CUSTOMER_ID  INVOICE_ID  AMOUNT_OF_INVOICE 
    3326660    1a     157$ 
    3326660    1b     112$ 
    3326660    1c     10$ 
    3326660    1d     94$ 
    3326660    1e     47$ 
    3326660    1f     35$ 
    3326660    1g     14$ 
    3326660    1h     132$ 
    3326660    1i     8$ 
    3326660    1j     60$ 
    3326660    1k     42$ 
    2789514    2a     86$ 
    2789514    2b     81$ 
    2789514    2c     99$ 
    2789514    2d     61$ 
    2789514    2e     16$ 
    2789514    2f     83$ 
    4931541    3a     11$ 
    4931541    3b     14$ 
    4931541    3c     17$ 
    4931541    3d     121$ 
    4931541    3e     35$ 
    4931541    3f     29$ 

私のターゲット表がある:

CUSTOMER_ID  TOTAL_DEBTS  CALCULATED_AMOUNT  INVOICES_ID 
    3326660    444$    444$    1a,1b,1f,1h,1i  
    2789514    165$    164$     2b,2f 
    4931541    121$    121$     3d 
例えば、私はテーブルを持っています10

私のテーブルには何千ものデータがあるので、パフォーマンスは私にとって非常に重要です。私はstackoverflowからコードを見つける: closest subset sum

しかし、パフォーマンスは低いです。私は、calculeted_amountとtotal_debtsの間で同じ値を見つけると、追加ループを停止する必要があります。

ありがとうございました。

+1

これはSQLにとって適切な問題ではありません。可能なすべての組み合わせを一般化し、どちらが最も近いかを確認する必要があります。 –

+0

@GordonLinoffと合意して、これを読んで、[wiki](https://en.wikipedia.org/wiki/Subset_sum_problem)に関するあなたの質問が理解できるようになります。 – Seyran

答えて

2

使用再帰クエリ:

demo

with 
    t1 as ( 
     select customer_id cid, total_debts dbt, invoice_id iid, amount_of_invoice amt, 
       row_number() over (partition by customer_id order by invoice_id) rn 
      from debts d join invoices i using (customer_id)), 
    t2 (cid, iid, ams, dbt, amt, sma, rn) as ( 
     select cid, cast(iid as varchar2(4000)), cast(amt as varchar2(4000)), 
       dbt, amt, amt, rn 
      from t1 
     union all 
     select t2.cid, 
       t2.iid || ', ' || t1.iid, 
       t2.ams || ', ' || t1.amt, 
       t2.dbt, t2.amt, t1.amt + t2.sma, t1.rn 
      from t2 
      join t1 on t1.cid = t2.cid and t1.rn > t2.rn and t2.sma + t1.amt <= t1.dbt), 
    t3 as (
     select t2.*, rank() over (partition by cid order by dbt - sma) rnk 
      from t2) 
select cid, iid, ams, dbt, sma from t3 where rnk = 1 

出力:

CID IID       AMS        DBT  SMA   
------- ---------------------------- ------------------------------ -------- -------- 
2789514 2b, 2f      81, 83        165  164 
3326660 1a, 1d, 1e, 1g, 1h   157, 94, 47, 14, 132     444  444 
3326660 1b, 1c, 1d, 1e, 1f, 1g, 1h 112, 10, 94, 47, 35, 14, 132   444  444 
3326660 1a, 1c, 1f, 1h, 1i, 1j, 1k 157, 10, 35, 132, 8, 60, 42   444  444 
3326660 1a, 1b, 1f, 1h, 1i   157, 112, 35, 132, 8     444  444 
4931541 3d       121         121  121 

6 rows selected 

サブクエリT1は、二つのテーブルを結合し、データを結合するために、次の使用の列rnが追加されます。 T2は階層的であり、仕事の主要部分を担い、総額が負債に達するまですべてのデータを結合します。 T3は、機能rankで最高のソリューションをフィルタリングします。 CID 3326660のように、可能な組み合わせは4つあります。

大量のデータの場合、再帰的サブクエリは遅く、この解決策は機能しません。警告を受けてください。

関連する問題