我提前为这个令人困惑的问题,文本墙和可怕的触发器道歉。我正在为零售商店设计一个小型数据库,该商店在店内接受订单,然后从现场仓库/库房中提供产品。
现在,订单实体与order_line实体之间存在一对多关系,而order_line实体又与产品(其本身存储在库存等中)具有多对一关系。 order_line实体是链接实体并解决了多对多关系,所以这一切都很好。只是为了澄清,这是每个产品的一个order_line。
我想要做的是当创建order_line(具有数量属性)时,我希望触发器首先检查相应的产品是否有足够的库存(因此如果数量为3,则库存必须至少为3),否则它必须抛出错误。
如果成功,我希望它相应地更新数量和库存属性。我还希望它为order_line添加一个小计值(我还没有尝试过),然后可以用来计算订单实体的总价值。
所以在这个阶段,我正在寻找一些指导,因为我现在对此非常困惑。
CREATE OR REPLACE TRIGGER check_order_line
BEFORE INSERT OR UPDATE ON order_line
for each row
BEGIN
select order_line.quantity, products.stock from order_lines right join products on order_line.product_no=products.product_no;
if(order_line.quantity>products.stock) then
RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock');
ELSE
products.stock := products.stock - quantity;
dbms_output.put('Successful');
END IF;
END;
.
run
我遇到的错误:
2/1 PL/SQL: SQL Statement ignored
2/49 PL/SQL: ORA-00942: table or view does not exist
3/1 PL/SQL: Statement ignored
3/15 PLS-00357: Table,View Or Sequence reference 'ORDER_LINE.QUANTITY'
not allowed in this context
我尝试了什么:
如果有人能指出我的话 方向,并指出任何我喜欢它的搞笑错误。
非常感谢你的时间,我为这种怪异的触发器伤到你的眼睛而道歉。
答案 0 :(得分:3)
对products.stock施加约束以强制执行该值> -1:
ALTER TABLE products add CONSTRAINT has_stock CHECK (stock >-1);
然后将update
和insert
作为单个交易执行。
UPDATE product SET products.stock = products.stock - quantity_required
WHERE product_id=id_of_product
INSERT INTO order_line ...............
COMMIT;
如果库存不足,交易将始终失败,您将不会遇到与触发器相关的问题。
假设您此时没有股票价格,您可以使用RETURNING
上的update
条款获取股票价格(您需要声明变量v_product_cost
以保留价值)例如:
UPDATE product SET products.stock = products.stock - quantity_required
WHERE product_id=id_of_product
RETURNING products.value INTO v_product_cost
然后,您可以在随后的插入中使用此值。
答案 1 :(得分:1)
run
命令没有意义。这是SQL Server语法。ORDER_LINES
(复数)。但触发器是在表ORDER_LINE
(单数)上定义的。我假设您没有ORDER_LINE
和ORDER_LINES
表,因此我希望您的查询可以引用ORDER_LINE
表。ORDER_LINE
上定义的,因此无法查询ORDER_LINE
。看起来您真的只想要导致触发器触发的行的信息,因此您实际上不需要加入ORDER_LINE
表。您只需要引用:NEW
记录中的属性。SELECT
语句需要对结果执行某些操作。据推测,您的目的是做一个SELECT ... INTO
局部变量。PRODUCTS
表,则需要执行实际的UPDATE
。把所有这些放在一起,我的猜测是你试图创建一个类似于
的触发器CREATE OR REPLACE TRIGGER check_order_line
BEFORE INSERT OR UPDATE ON order_line
for each row
DECLARE
l_current_stock products.stock%type;
BEGIN
select products.stock
into l_current_stock
from products
where product_no = :new.product_no;
if(:new.quantity > l_current_stock) then
RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock');
else
update products
set stock := stock - :new.quantity
where product_no := :new.product_no;
end if;
END;
然而,所有这一切,触发器通常不是解决此类问题的正确方法。从维护的角度来看,如果没有别的东西,那么插入所有PROCESS_ORDER
行并更新所有ORDER_LINE
行的存储过程PRODUCTS
将更容易遵循和调试。嵌入的业务逻辑越多,就越难以跟踪应用程序的流程,并且更容易最终得到一个几乎不可能放松的无意更新的老鼠窝。
另外,请注意多用户系统中会发生什么。会话A可以查询PRODUCTS
表并查看STOCK
的5并接受该产品的4个单位的订单。但是在会话A发出提交之前,会话B也会查询PRODUCTS
表的同一行,看到相同的STOCK
为5,并接受3个单位的订单。会话B的UPDATE
语句将阻塞,直到会话A提交。但是如果A提交和B提交,则两个订单都将被输入,PRODUCTS
表将显示-2的STOCK
。这就是为什么你需要凯文建议的CHECK
约束
ALTER TABLE products
ADD CONSTRAINT chk_positive_stock CHECK( stock >= 0 );