我正在寻找一个查询,根据item_order将$ 1100分配到下面的每张发票。此外,如果partial_payment_allowed设置为' N'然后,只有当分配金额大于invoice_amt时,才会发生上述金额的分配,否则应该跳过该行并继续下一个发票。
Task.Factory.StartNew()
因此,如果我们通过$ 1100,查询的最终结果将是
Item_order inv_amount Partial_pmt_allowed
1 1256 N
2 1134 N
3 800 N
4 200 Y
5 156 Y
我们正在努力避免循环,任何评论都非常感谢。谢谢
答案 0 :(得分:3)
这是SQL MODEL
子句的一个很好的用例。
-- Set up test data (since I don't have your table)
with inv_raw (item_order, inv_amount, partial_pmt_allowed) as (
SELECT 1, 1256, 'N' FROM DUAL UNION ALL
SELECT 2, 1134, 'N' FROM DUAL UNION ALL
SELECT 3, 800, 'N' FROM DUAL UNION ALL
SELECT 4, 200, 'Y' FROM DUAL UNION ALL
SELECT 5, 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
( SELECT dense_rank() OVER ( PARTITION BY NULL ORDER BY item_order ), item_order, inv_amount, partial_pmt_allowed FROM inv_raw ),
-- Give us a way to input the payment amount
param as ( SELECT 1100 p_payment_amount FROM DUAL )
-- The actual query starts here
SELECT 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] = CASE WHEN remaining_in[CV()] >= inv_amount[CV()] OR partial_pmt_allowed[CV()] = 'Y' THEN LEAST(inv_amount[CV()], remaining_in[CV()]) ELSE 0 END,
-- The amount we carry out is the amount we brought in minus what we applied
remaining_out[ANY] = remaining_in[CV()] - applied[CV()]
)
ORDER BY item_order;
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 |
答案 1 :(得分:2)
我使用绑定变量person
输入收到的付款。以下是SQL * Plus中需要的准备工作,其他前端应用程序(如SQL Developer和Toad等)都有自己的机制。我还准备了一个广泛的专栏。
准备(SQL * Plus):
:pmt
解决方案是递归查询,因此需要Oracle 11.1或更高版本。我以一种需要Oracle 11.2或更高版本的形式编写它(我在声明因子子查询时声明了列别名),但如果需要,可以很容易地在11.1中使用它。
<强>查询强>:
SQL> variable pmt number
SQL> exec :pmt := 1100;
PL/SQL procedure successfully completed.
SQL> column partial_pmt_allowed format a20
结果(使用查询中定义的输入数据和&#34;收到的付款&#34;作为绑定变量with
-- begin test data (not part of the solution)
test_data ( item_order, inv_amt, partial_pmt_allowed ) as (
select 1, 1256, 'N' from dual union all
select 2, 1134, 'N' from dual union all
select 3, 800, 'N' from dual union all
select 4, 200, 'Y' from dual union all
select 5, 156, 'Y' from dual union all
select 6, 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 (
select 0, 0, '', 0, :pmt
from dual
union all
select t.item_order, t.inv_amt, t.partial_pmt_allowed,
case when r.balance >= t.inv_amt then t.inv_amt
when t.partial_pmt_allowed = 'Y' then r.balance
else 0 end,
case when r.balance >= t.inv_amt then r.balance - t.inv_amt
when t.partial_pmt_allowed = 'Y' then 0
else r.balance end
from test_data t join r on t.item_order = 1 + r.item_order
)
select *
from r
where item_order != 0
order by item_order
;
传入的值1100):
:pmt