Skip to content Skip to sidebar Skip to footer

Payment Distrubution Oracle Sql Query

I am looking for a query where $1100 gets distributed to each invoice below based on the item_order. Also, if partial_payment_allowed is set to 'N' then distribution of the above a

Solution 1:

This is a good use case for the SQL MODEL clause.

-- Set up test data (since I don't have your table)with inv_raw (item_order, inv_amount, partial_pmt_allowed) as ( 
SELECT1, 1256, 'N'FROM DUAL UNIONALLSELECT2, 1134, 'N'FROM DUAL UNIONALLSELECT3, 800, 'N'FROM DUAL UNIONALLSELECT4, 200, 'Y'FROM DUAL UNIONALLSELECT5, 156, 'Y'FROM DUAL),
-- Ensure that the column we are ordering by is densely populated
inv_dense (dense_item_order, item_order, inv_amount, partial_pmt_allowed) as 
( SELECTdense_rank() OVER ( PARTITIONBYNULLORDERBY item_order ), item_order, inv_amount, partial_pmt_allowed FROM inv_raw ),
-- Give us a way to input the payment amount
param as ( SELECT1100 p_payment_amount FROM DUAL )
-- The actual query starts hereSELECT item_order,
 inv_amount,
 partial_pmt_allowed,
--remaining_in,
applied dist_amount,
remaining_out balance_amt
 FROM param, inv_dense
MODEL 
DIMENSION BY ( dense_item_order )
MEASURES ( p_payment_amount, item_order, inv_amount, partial_pmt_allowed, 0 applied, 0 remaining_in, 0 remaining_out )
RULES AUTOMATIC ORDER (
-- The amount carried into the first row is the payment amount
remaining_in[1] = p_payment_amount[1],
-- The amount carried into subsequent rows is the amount we carried out of the prior row
remaining_in[dense_item_order >1] = remaining_out[CV()-1],
-- The amount applied depends on whether the amount remaining can cover the invoice -- and whether partial payments are allowed
applied[ANY] =CASEWHEN remaining_in[CV()] >= inv_amount[CV()] OR partial_pmt_allowed[CV()] ='Y'THEN LEAST(inv_amount[CV()], remaining_in[CV()]) ELSE0END,
-- The amount we carry out is the amount we brought in minus what we applied
remaining_out[ANY] = remaining_in[CV()] - applied[CV()] 
)
ORDERBY item_order;

RESULT

ITEM_ORDER |INV_AMOUNT |PARTIAL_PMT_ALLOWED |DIST_AMOUNT |BALANCE_AMT |
-----------|-----------|--------------------|------------|------------|
1          |1256       |N                   |0           |1100        |
2          |1134       |N                   |0           |1100        |
3          |800        |N                   |800         |300         |
4          |200        |Y                   |200         |100         |
5          |156        |Y                   |100         |0           |

Solution 2:

I use a bind variable :pmt to input the payment received. Here is the prep needed in SQL*Plus, other front-end apps like SQL Developer and Toad etc. have their own mechanisms. I also prepared for a wide column.

Preparation (SQL*Plus):

SQL> variable pmt number
SQL>exec :pmt :=1100;

PL/SQLprocedure successfully completed.
SQL>column partial_pmt_allowed format a20

The solution is a recursive query, so it requires Oracle 11.1 or above. I wrote it in a form that requires Oracle 11.2 or above (I declare column aliases when I declare factored subqueries), but that can be changed very easily to work in 11.1 if needed.

Query:

with--  begin test data (not part of the solution)
     test_data ( item_order, inv_amt, partial_pmt_allowed ) as (
       select1, 1256, 'N'from dual unionallselect2, 1134, 'N'from dual unionallselect3,  800, 'N'from dual unionallselect4,  200, 'Y'from dual unionallselect5,  156, 'Y'from dual unionallselect6,   30, 'N'from dual
     ),
--  end of test data; the solution (SQL query) includes just --      the keyword "with" from above and continues below this line.
     r ( item_order, inv_amt, partial_pmt_allowed, dist_amt, balance ) as (
       select0, 0, '', 0, :pmt
         from dual
       unionallselect t.item_order, t.inv_amt, t.partial_pmt_allowed,
              casewhen r.balance >= t.inv_amt then t.inv_amt
                   when t.partial_pmt_allowed ='Y'then r.balance
                   else0end,
              casewhen r.balance >= t.inv_amt then r.balance - t.inv_amt
                   when t.partial_pmt_allowed ='Y'then0else r.balance endfrom   test_data t join r on t.item_order =1+ r.item_order
     )
select*from     r
where    item_order !=0orderby item_order
;

Results (with the input data defined in the query and the "payment received" value of 1100 passed in as the bind variable :pmt):

ITEM_ORDERINV_AMTPARTIAL_PMT_ALLOWEDDIST_AMTBALANCE------------------------------------------------------------11256 N0110021134 N011003800N8003004200Y2001005156Y1000630N006rowsselected.

Post a Comment for "Payment Distrubution Oracle Sql Query"