我有一张叫书的桌子。该表有 3 列,即 id、价格和折扣。如果价格大于 200,则折扣应为 20%。在 Book 表中插入数据时,应根据价格值更新折扣值。在 Book 表中插入或更新数据时如何处理?
请提供所有可能的解决方案。我不想执行存储过程。让我们假设当用户在 Book 表中插入/更新数据时,他不执行函数或过程。
请提供解决方案。
我有一张叫书的桌子。该表有 3 列,即 id、价格和折扣。如果价格大于 200,则折扣应为 20%。在 Book 表中插入数据时,应根据价格值更新折扣值。在 Book 表中插入或更新数据时如何处理?
请提供所有可能的解决方案。我不想执行存储过程。让我们假设当用户在 Book 表中插入/更新数据时,他不执行函数或过程。
请提供解决方案。
如果您不想使用存储过程,那么唯一的其他选择是触发器。
create or replace trigger book_discount_rule
before insert, update on BOOK
for each row
begin
if :new.price > 200
then
:new.discount := 20;
else
:new.discount := 0;
end if;
end;
我个人不喜欢这个解决方案,正是因为触发器是不可见的。也就是说,如果用户运行这个插入语句......
insert into book
values (book_id_seq.nextval, 250, 30)
/
...他们可能会感到困惑,为什么存储的 DISCOUNT 与他们提交的值不同。我宁愿使用存储过程来执行业务规则。
无论哪种方式,在现实生活中,我宁愿通过 API 实现规则,而不是对值进行硬编码。但这是一个品味问题。
正如 Jeffrey 所指出的,最好使用表上的检查约束来备份触发器(或过程),以确保 DISCOUNT 适合价格。
alter table book
add constraint book_discount_ck
check ((price > 200 and discount = 20) or discount = 0)
/
在没有存储过程或触发器的情况下应用约束要求用户了解业务规则。不幸的是,Oracle 没有提供将特定错误消息附加到我们的检查约束的机制。使用有意义的消息引发特定于上下文的异常的能力是存储过程的优点之一。
不使用任何存储过程:
ALTER TABLE "Book" ADD (
CONSTRAINT discount_check
CHECK (price < 200 OR discount = 0.2)
);
这样,除非插入适当的价格和折扣值,否则任何人都无法插入或更新图书。*
*(为了防弹,您也可以向这些列添加 NOT NULL 约束)
如果折扣始终只是价格的函数,那么我建议将其作为视图中的计算列。给定一个Books
包含 和 列id
的表price
,创建一个像这样的视图:
CREATE VIEW books_view AS (
SELECT
id,
price,
CASE WHEN price > 200 THEN 0.20 ELSE 0 END discount
FROM books
);
这样,用户就不能将折扣设置为不正确的值。使用触发解决方案,折扣可以在插入时正确设置,但可以通过以后的更新进行更改。