我仍然在为一个小型零售商店开发这个数据库(一种情况,谢天谢地!)我正在尝试用触发器解决这个问题。
相关实体是客户,付款和订单。付款是另外两个之间的链接实体,因此一个客户可以进行多笔付款,一个订单可以有多笔付款(不寻常但仍然可能),这一切都很好。
触发器:
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
此刻它运作正常。基本上,在客户的订单被标记为“已调度”之前,付款状态必须为“成功”。如果它为null或“失败”,则触发器将像“哦,不,你没有!” (但用更正式的话说)按预期工作。但是,如果应用业务规则“订单可以有多笔付款”,则触发器需要检查我收到此错误的所有相关付款,因为SELECT INTO
语句只打算返回一行。
我已经阅读过游标了一下,但我想我在这里走得太远了 - 请问有人会提出一些解决方案吗?
答案 0 :(得分:9)
那么,如果订单可以有多笔付款,您如何确定是否全额付款?据推测,每笔付款都有一笔金额,订单总金额到期,因此您需要检查是否已支付全部金额。在我看来,你可以通过获得所有成功付款的总和,然后将其与应付总金额进行比较来实现。基本查询将是:
SELECT SUM(payment_amount)
INTO total_payment_amount
FROM payment
WHERE order_no = :new.order_no
AND payment_status = 'Successful';
答案 1 :(得分:9)
总的来说,你有很多应用程序级别的逻辑绑定到一个触发器,这会让你在路上遇到很多麻烦,因为你不知道什么时候以及为什么更新值你的相关表格。
Dave Costa对处理付款有一个很好的建议,我会创建一个或多个相关的PL / SQL包,其中包含清晰编写的函数和过程,用于处理您尝试在此触发器中执行的应用程序级逻辑
触发器应该很少使用 - 通常是在从序列设置主键或审核对表的访问时。
答案 2 :(得分:4)
我知道这是一个老问题,但今天在客户端生产数据库中出现了类似的问题。有时可以通过主键(可能是序列号)按降序排序并使用“rownum = 1”。当然,您应该找出为什么您有多个符合条件的记录并修复允许它的应用程序中的错误。