Oracle - ORA-01422: 精确获取返回的行数多于请求的行数

发布于 2024-12-20 19:17:27 字数 1142 浏览 4 评论 0原文

我仍在为一家小型零售商店开发这个数据库(谢天谢地,这是一个场景!),目前正在尝试使用触发器来解决此问题。

相关实体是客户、付款和订单。付款是其他两者之间的链接实体,因此一个客户可以进行多次付款,一个订单可以进行多次付款(不寻常但仍然可能),这都很好。

触发器:

CREATE OR REPLACE TRIGGER Check_Payment_Status  
BEFORE UPDATE OF Order_Status ON Customer_Order 

for each row
  DECLARE paymentStatus payment.payment_status%type;
  BEGIN

    select payment.payment_status into paymentStatus
    from payment
    where order_no = :new.order_no;

    IF (paymentStatus ='Failed' OR paymentStatus IS NULL ) then  
      RAISE_APPLICATION_ERROR(-20103, 'The full payment has not been made so the order cannot be     processed further until then.');
      update customer_order set order_status='Delayed' where order_no= :new.order_no;
    END IF;

    IF (paymentStatus ='Successful' ) then  
      update payment set payment_date=SYSDATE where order_no= :new.order_no;
    END IF;


  END; 
. 
run

目前工作正常。基本上,在将客户的订单标记为“已发货”之前,付款状态必须为“成功”。如果它为空或“失败”,触发器将类似于“哦,不,你不!” (但用更正式的话来说)正在按预期工作。但是,如果应用业务规则“一个订单可以有多次付款”,则触发器需要检查所有相关付款,这就是我收到此错误的地方,因为 SELECT INTO 语句打算返回一行仅有的。

我已经阅读了一些关于游标的内容,但我认为我在这里有点太过分了 - 有人能建议一些解决方案吗?

I'm still working on this database for a small retail store (a scenario, thankfully!) and am currently trying to fix this issue with a trigger.

The relevant entities are Customer, Payment and Order. Payment is a link entity between the other two, so one Customer could make many payments and one order could have many payments (unusual but still possible) and that's all fine.

The trigger:

CREATE OR REPLACE TRIGGER Check_Payment_Status  
BEFORE UPDATE OF Order_Status ON Customer_Order 

for each row
  DECLARE paymentStatus payment.payment_status%type;
  BEGIN

    select payment.payment_status into paymentStatus
    from payment
    where order_no = :new.order_no;

    IF (paymentStatus ='Failed' OR paymentStatus IS NULL ) then  
      RAISE_APPLICATION_ERROR(-20103, 'The full payment has not been made so the order cannot be     processed further until then.');
      update customer_order set order_status='Delayed' where order_no= :new.order_no;
    END IF;

    IF (paymentStatus ='Successful' ) then  
      update payment set payment_date=SYSDATE where order_no= :new.order_no;
    END IF;


  END; 
. 
run

It works okay at the moment. Basically, before a customer's order can be flagged as "Dispatched" the payment status must be "Successful". If it's null or "Failed" the trigger will be like "oh no you don't!" (but in more formal words) which is working as intended. However, if one applies the business rule "an order can have many payments" the trigger needs to check all relevant payments which is where I get this error, as the SELECT INTO statement is intending to return one row only.

I've read up on Cursors a bit but I think I'm going a bit too far here - would anyone suggest some solutions, please?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不…忘初心 2024-12-27 19:17:27

那么,如果一个订单可以多次付款,那么如何判断是否全额付款呢?想必每笔付款都有金额,并且订单有总应付金额,因此您需要检查是否已支付全部金额。在我看来,您可以通过获取所有成功付款的总和然后将其与应付总额进行比较来做到这一点。基本查询是:

  SELECT SUM(payment_amount)
    INTO total_payment_amount
    FROM payment
    WHERE order_no = :new.order_no
      AND payment_status = 'Successful';

Well, if an order can have multiple payments, how do you decide if it is paid in full? Presumably each payment has an amount, and the order has a total amount due, so you need to check that the full amount has been paid. Seems to me you can do this by getting the sum of all successful payments then comparing it to the total amount due. The basic query would be:

  SELECT SUM(payment_amount)
    INTO total_payment_amount
    FROM payment
    WHERE order_no = :new.order_no
      AND payment_status = 'Successful';
梦冥 2024-12-27 19:17:27

一般来说,您有很多应用程序级逻辑绑定到触发器中,这会给您带来很多麻烦,因为您不会知道相关表中的值何时以及为何更新。

Dave Costa 对于处理付款有一个很好的建议,我将创建一个或多个相关的 PL/SQL 包,其中包含清晰编写的函数和过程,用于处理您尝试在此触发器中执行的应用程序级逻辑。

触发器应该很少使用——通常是当您从序列设置主键或审核对表的访问时。

On a general note, you have a lot of application-level logic tied up into a trigger, which will get you into a lot of trouble down the road because you're not going to know when and why values were updated in your related tables.

Dave Costa has a good suggestion for handling the payments, and I would create one or more related PL/SQL packages with clearly-written functions and procedures for handling the application-level logic that you're trying to perform in this trigger.

Triggers should be used very rarely -- typically when you're setting the primary key from a sequence or auditing access to a table.

把梦留给海 2024-12-27 19:17:27

我知道这是一个老问题,但今天在客户端生产数据库中出现了类似的问题。有时按主键(可能是序列号)按降序排序并使用“rownum=1”可能很有用。当然,您应该找出为什么您有多个符合条件的记录,并修复应用程序中允许这样做的错误。

I know this is an old question, but similar came up today in a client production database. Sometimes can be useful to order by the primary key, perhaps a sequence number, in descending order and use "rownum=1". Naturally you should find out why you have more than one record that matches the criteria and fix the bug in your application that allows it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文