无参数的求解过程

时间:2018-12-14 05:03:04

标签: oracle loops stored-procedures plsql database-cursor

嘿,大家在这里看看你们是否可以帮助我解决我遇到的过程问题。长话短说,我做了一张新桌子,叫做

Create Table ClientHistoricalPurchases(
ClientID varchar2(6) constraint clientidhistorical references Clients,
DistinctProducts number (9),
TotalProducts number(9), 
TotalCost number (9,2),
Primary Key (ClientID));

我想通过运行主要从下表读取的过程来填充/更新此表:

create table OrderDetails(
OrderID varchar2(6) CONSTRAINT orddetpk PRIMARY KEY,
ProductID varchar2(6) CONSTRAINT prdfk REFERENCES Products ,
UnitPrice number(10,2),
Quantity number(4),
Discount number(3),
ShippingDate date);

我使用另外两个称为Orders和Clients的表进行了几次联接,但是这些联接是使用主键/ FK进行的简单联接。

因此,此过程的目标是,当我运行该过程时,我想遍历订单详细信息,并要计算客户购买的产品的不同数量,总产品和总购买金额,并且我想更新如果新记录不在新ClientHistoricalPurchases表中,则该记录具有新值,如果不存在,我想为其添加新记录。所以这是我写的,但给我错误:

Create or Replace Procedure Update_ClientHistPurch as

Cursor C1 is 
Select orderid, orders.clientid, productid, unitprice, quantity, discount
from orderdetails
Inner join orders on orderdetails.orderid = orders.clientid
for update of TotalCost;

PurchaseRow c1%RowType;
DistinctProducts orderdetails.quantity%type;
TotalProducts orderdetails.quantity%type;
ProposedNewBalance orderdetails.unitprice%type;

Begin
Begin
Begin
Begin
Open C1;
Fetch c1 into PurchaseRow;

While c1% Found Loop 
Select count(distinct productid)
into DistinctProducts
from orderdetails
Inner join orders on orderdetails.orderid = orders.orderid
Inner join clients on orders.clientid = clients.clientid
where clients.clientid = purchaserow.clientid;
end;

Select count(ProductID)
into TotalProducts
from orderdetails
Inner join orders on orderdetails.orderid = orders.orderid
Inner join clients on orders.clientid = clients.clientid
where clients.clientid = purchaserow.clientid;
end;

Select sum((unitprice * quantity) - discount)
into ProposedNewBalance
from orderdetails
Inner join orders on orderdetails.orderid = orders.orderid
Inner join clients on orders.clientid = clients.clientid
where clients.clientid = purchaserow.clientid;
end;

If purchaserow.clientid not in ClientHistoricalpurchases.clientid then
insert into ClientHistoricalPurchases values    (purchaserow.clientid,DistinctProducts, TotalProducts, ProposedNewBalance);
End if;

If purchaserow.clientid in ClientHistoricalPurchases.clientid then
Update Clienthistoricalpurchases
set clienthistoricalpurchases.distinctproducts = distinctproducts,    clienthistoricalpurchases.totalproducts = totalproducts,    clienthistoricalpurchases.totalcost = ProposedNewBalance
    where purchaserow.clientid = clienthistoricalpurchases.clientid;
end if;
end loop;
end;

以下是错误:

  

错误(27,4):PLS-00103:遇到符号“;”当期待一个    以下内容:循环用符号“循环”代替“;”。    继续。
  错误(33,7):PLS-00103:遇到符号“ JOIN”   当期望以下之一时:对于有   相交的减号在连接处开始合并

任何帮助都是值得赞赏的家伙。谢谢!

2 个答案:

答案 0 :(得分:2)

除了已经给您的评论和答案之外,我相信您已经使程序过于复杂。您正在非常有步骤地进行操作,而不是按照应有的方式进行思考。您还可以在三个基本相同的查询(例如,相同的表,联接条件和谓词)中获得汇总列-您可以将它们全部组合在一起,以在单个查询中获得三个结果。

如果该客户的行尚不存在,您似乎正在尝试将其插入到clienthistoricalpurchases表中,否则您将更新该行。那立即向我尖叫“合并声明”。

结合所有这些,我认为您当前的过程应该只包含一个合并语句:

MERGE INTO clienthistoricalpurchases tgt
  USING (SELECT clients.client_id,
                COUNT(DISTINCT od.productid) distinct_products,
                COUNT(od.productid) total_products,
                SUM((od.unitprice * od.quantity) - od.discount) proposed_new_balance
         FROM   orderdetails od
         INNER  JOIN orders
         ON     orderdetails.orderid = orders.orderid
         INNER  JOIN clients
         ON     orders.clientid = clients.clientid
         GROUP BY clients.client_id) src
  ON (tgt.clientid = src.client_id)
WHEN NOT MATCHED THEN
  INSERT (tgt.clientid,
          tgt.distinctproducts,
          tgt.totalproducts,
          tgt.totalcost) 
  VALUES (src.clientid,
          src.distinct_products,
          src.total_products,
          src.proposed_new_balance)
WHEN MATCHED THEN
  UPDATE SET tgt.distinctproducts = src.distinct_products,
             tgt.totalproducts = src.total_products,
             tgt.totalcost = src.proposed_new_balance;

但是,我对您当前的逻辑和/或数据模型有些担心。

您似乎希望每个clientid最多出现一行在clienthistoricalpurchases中。如果一个clientid有两个或多个不同的订单怎么办?当前,您将覆盖任何现有行。

此外,您是否真的想在每次运行订单时在所有订单上应用此逻辑?

答案 1 :(得分:0)

代码的第28行,即END之后的第一个WHILE应该是END LOOP