Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
支付分发oracle sql查询_Sql_Oracle - Fatal编程技术网

支付分发oracle sql查询

支付分发oracle sql查询,sql,oracle,Sql,Oracle,我正在寻找一个查询,其中1100美元将根据商品订单分配给下面的每张发票。此外,如果允许部分付款设置为“N”,则仅当分配金额大于发票金额时,才应分配上述金额,否则应跳过该行并继续分配到下一张发票 Item_order inv_amount Partial_pmt_allowed 1 1256 N 2 1134 N 3 800 N 4 200 Y 5

我正在寻找一个查询,其中1100美元将根据商品订单分配给下面的每张发票。此外,如果允许部分付款设置为“N”,则仅当分配金额大于发票金额时,才应分配上述金额,否则应跳过该行并继续分配到下一张发票

Item_order inv_amount   Partial_pmt_allowed
1          1256         N
2          1134         N
3           800         N
4           200         Y
5           156         Y
因此,如果我们超过1100美元,查询的最终结果将是

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

我们正在努力避免循环,非常感谢您的评论。谢谢您这是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;
结果
这是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;
结果
我使用绑定变量
:pmt
输入收到的付款。这是SQL*中需要的准备工作。另外,其他前端应用程序,如SQL Developer和Toad等,都有自己的机制。我还准备了一篇专栏文章

准备(SQL*Plus)

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

PL/SQL procedure successfully completed.
SQL> column partial_pmt_allowed format a20
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
;
该解决方案是递归查询,因此需要Oracle 11.1或更高版本。我以一种需要Oracle11.2或更高版本的形式编写了它(我在声明带系数的子查询时声明了列别名),但如果需要,可以很容易地将其更改为在11.1中工作

查询

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

PL/SQL procedure successfully completed.
SQL> column partial_pmt_allowed format a20
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
):


我使用绑定变量
:pmt
输入收到的付款。这是SQL*中需要的准备工作。另外,其他前端应用程序,如SQL Developer和Toad等,都有自己的机制。我还准备了一篇专栏文章

准备(SQL*Plus)

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

PL/SQL procedure successfully completed.
SQL> column partial_pmt_allowed format a20
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
;
该解决方案是递归查询,因此需要Oracle 11.1或更高版本。我以一种需要Oracle11.2或更高版本的形式编写了它(我在声明带系数的子查询时声明了列别名),但如果需要,可以很容易地将其更改为在11.1中工作

查询

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

PL/SQL procedure successfully completed.
SQL> column partial_pmt_allowed format a20
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
):


这个问题对我来说有点不清楚。最后一行的dist_金额中的200是从哪里来的?如果全额1000美元分配到该发票,那么第40行的balance_金额不应该是0吗?好吧,你尝试了什么?这个问题对我来说有点不清楚。最后一行的dist\u amount中的200从哪里来,如果全额1000美元分配给该发票,那么第40行的balance\u amount不应该是0?好吧,您尝试了什么?如果您谈论的是大量数据,也可以不使用
inv\u dense
公共表表达式来实现更好的性能。谢谢Mathew Mcpeak。很好。您好,马修,您知道我是否可以使用model query来实现与上述相同的目的,但用于多个账户的多笔付款。例如,这里是我的数据是。例如,如果每个帐户都由
帐户编号
列标识,则可以直接在
模型
关键字后添加
分区(帐户编号)
。以下是数据。与发布的初始问题不同,分配金额可以根据帐户而变化。cr_amt是需要分配的金额。项目订单库存金额部分付款账户金额cr金额1 1256 N 12 1000 2 1134 N 12 1000 1 800 N 13 1200 2 200Y 13 1200如果您谈论的是大量数据,也可以在没有
inv_dense
公共表表达式的情况下使用,以获得更好的性能。谢谢Mathew Mcpeak。很好。您好,马修,您知道我是否可以使用model query来实现与上述相同的目的,但用于多个账户的多笔付款。例如,这里是我的数据是。例如,如果每个帐户都由
帐户编号
列标识,则可以直接在
模型
关键字后添加
分区(帐户编号)
。以下是数据。与发布的初始问题不同,分配金额可以根据帐户而变化。cr_amt是需要分配的金额。项目订单库存金额部分付款账户金额cr金额1 1256 N 12 1000 2 1134 N 12 1000 1 800 N 13 1200 2 200Y 13 1200