如何在oracle中执行触发器和过程
How to execute trigger and procedure in oracle
我正在做我的项目 'Supermarket Billing Management System' 因为我是初学者,所以在制作项目时遇到了很多问题。在这里,我已经创建了一个触发器和一个过程,但我不知道如何执行它,我已经为单个产品的总价创建了一个触发器,即 ProdTotal = ProdPrice * ProdQuantity;
。
这意味着每当用户在产品 table 中输入一些数据时,必须执行此触发器,但我不知道如何执行它,同样,我创建了一个程序来计算所有的总价单个客户购买的产品。就像你去超市或任何商店购买物品后,你会收到一张账单,上面有最终的总金额。我什至不确定我的程序代码是对还是错,尽管它已成功创建,但我不确定它是否会给我我想要的确切输出,所以如果你能帮助我,请告诉我,我从不同的网站和许多 youtube 视频中进行了很多研究,但说真的,我不知道如何解决它,所以请帮助我!
代码:
产品table
create table Products
( ProdId number primary key,
ProdNum number not null unique,
ProdName varchar2(15),
ProdPrice int,
ProdQuantity int,
ProdCustId int references Customers,
ProdOrdId int references Orders,
ProdStoreId int references Stores
);
付款table
create table Payments
( PayId int primary key,
PayDate date,
ProdTotal int,
FinalTotal int,
PayOrdId int references orders,
PayProdId int references Products,
PayCustId int references Customers
);
触发码
create trigger PROD_TOTAL
AFTER INSERT ON Products
BEGIN
UPDATE Payments
SET ProdTotal = (SELECT Products.ProdPrice * Products.ProdQuantity FROM Products);
END;
/
程序代码
create procedure FINAL_TOTAL(C IN NUMBER, T OUT NUMBER)
IS
BEGIN
UPDATE Payments
SET FinalTotal = FinalTotal + ProdTotal
WHERE PayCustId = C;
Commit;
SELECT FinalTotal into T FROM Payments WHERE PayCustId = C;
END;
/
在产品中插入语句 table:
insert into Products values(1,1001,'Syrup',30,4,1,1,1);
在付款中插入报表 table:
insert into Payments(PayId, PayDate, PayOrdID, PayProdId, PayCustId)
values(1,date'2020-10-07',1,1,1);
输出:
select * from products;
PRODID PRODNUM PRODNAME PRODPRICE PRODQUANTITY PRODCUSTID
---------- ---------- --------------- ---------- ------------ ----------
PRODORDID PRODSTOREID
---------- -----------
1 1001 Syrup 30 4 1
1 1
select * from Payments;
PAYID PAYDATE PRODTOTAL FINALTOTAL PAYORDID PAYPRODID PAYCUSTID
---------- --------- ---------- ---------- ---------- ---------- ----------
1 07-OCT-20 1 1 1
现在在这里,您可以看到 PRODTOTAL 和 FINALTOTAL 列是空白的,我知道为什么它是空白的,因为我没有输入任何值。我之所以没有在这两列中输入任何值,是因为我想,系统应该在触发器和程序的帮助下自动计算该计算,我什至不能删除触发器和程序,因为它在我们的程序中是强制性的项目使用这两个概念。所以请帮助我!!!
如前所述,首先尝试根据您的要求进行正确的设计。您可以通过正确设计数据库模式来实施许多约束。
尽可能远离触发器和PL/SQL。它最终会迫使您进行更好的设计,并会有所回报。
在将触发器用于业务逻辑之前,请尝试将视图用于可以选择的事物。这就是数据库的用途。
当您“完成”后,测试性能,如果性能不理想,则改进您的架构。如果没有任何帮助,请开始为业务逻辑使用触发器。
我把我正在谈论的观点放在一起 sample。我希望它能帮助你入门。
create table Products (
ProdId number generated always as identity primary key
, ProdName varchar2(20) not null
);
create table Stores (
StoreId number generated always as identity primary key
, StoreName varchar2(20) not null
);
create table Customers (
CustomerId number generated always as identity primary key
, CustomerName varchar2(20) not null
);
create table Prices (
PriceId number generated always as identity primary key
, ProdId number not null
, Price number
, ValidFrom date default on null sysdate
, constraint fk_Prices_Product foreign key (ProdId) references Products (ProdId)
);
create unique index uniq_prices_product_price on Prices (ProdId, ValidFrom);
create table Orders (
OrderId number generated always as identity primary key
, CustomerId number not null
, StoreId number not null
, OrderedAt date default on null sysdate
, constraint fk_Orders_Customer foreign key (CustomerId) references Customers (CustomerId)
, constraint fk_Orders_Store foreign key (StoreId) references Stores (StoreId)
);
create table OrderLines (
OrderLineId number generated always as identity primary key
, OrderId number not null
, ProdId number not null
, ProdQuantity number not null
, constraint fk_OrderLines_Order foreign key (OrderId) references Orders (OrderId)
, constraint fk_OrderLines_Prod foreign key (ProdId) references Products (ProdId)
);
create table Payments (
PaymentId number generated always as identity primary key
, OrderId number not null
, PaidAt date default on null sysdate
, PaidAmount number not null
, constraint fk_Payments_Order foreign key (OrderId) references Orders (OrderId)
);
create view Prices_V as
select
p.*
, coalesce(
lead(p.ValidFrom) over (partition by p.ProdId order by p.ValidFrom)
, to_date('9999', 'YYYY')
) ValidTo
from Prices p;
create view Orders_V as
select
o.*
, (
select sum(ol.ProdQuantity * p.Price)
from OrderLines ol
join Prices_V p on (p.ProdId = ol.ProdId and o.OrderedAt between p.ValidFrom and p.ValidTo)
where o.OrderId = ol.OrderId
) Total
, (
select sum(PaidAmount)
from Payments p
where p.OrderId = o.OrderId
) TotalPaid
from Orders o;
insert into Products(ProdName)
select 'Prod A' from dual union all
select 'Prod B' from dual;
insert into Stores(StoreName) values ('Store A');
insert into Customers(CustomerName)
select 'Customer A' from dual union all
select 'Customer B' from dual;
insert into Prices(ProdId, Price, ValidFrom)
select 1, 10, sysdate - 10 from dual union all
select 1, 12, sysdate - 2 from dual union all
select 1, 14, sysdate + 3 from dual union all
select 2, 100, sysdate - 10 from dual union all
select 2, 90, sysdate - 2 from dual union all
select 2, null, sysdate + 5 from dual;
insert into Orders(CustomerId, StoreId, OrderedAt)
select 1 cid, 1 stoid, sysdate - 5 from dual union all
select 2, 1, sysdate - 5 from dual union all
select 2, 1, sysdate - 1 from dual;
insert into OrderLines(OrderId, ProdId, ProdQuantity)
select 1 ordid, 1 prodid, 3 prodquant from dual union all
select 1, 2, 2 from dual union all
select 2, 2, 10 from dual union all
select 3, 2, 10 from dual;
insert into Payments(OrderId, PaidAmount) values (2, 500);
select * from Prices_V order by ProdId, ValidFrom;
select * from OrderLines order by OrderId, ProdId;
select * from Orders_v order by OrderId;
其中的一些想法:
- 价格存储在单独的 table 中,参考产品并具有有效性,因此产品价格可以随时间变化。价格视图添加了
ValidTo
列,因此更易于使用
- 价格有一个唯一索引,因此我们不能同时为同一产品提供 2 个价格
- 您可以按顺序排列多个项目,这就是为什么存在
Orders
和 OrderLines
table 一对多关系的原因
- 在
Order_V
中显示支付总额(使用 Payments
上的子查询)并显示总订单值(使用 OrderLines
和 Prices
上的子查询, 订单日期用于获取正确时期的价格)
根据模式,您将了解哪些可以表示,哪些不能。让它符合您的要求是您的工作:)
现在我谈到了您所说的触发器和过程在您的项目中是强制性的。因此我有一个提议:
- 创建一个允许用户为产品创建新价格的程序。它绝对应该检查有效性不是从过去开始的。然后实施另一个允许更改有效期的日期(也不能在过去结束)。然后,您可以撤销对产品 table 的任何 insert/update 特权,并强制用户使用将包含此业务逻辑的过程。
- 创建一个 table
PricesLog
并在 Prices
上触发,这将插入 PriceId、old.Price、new.Price、sysdate 和 User
登录任何 inserts/updates 到价格 table.
我正在做我的项目 'Supermarket Billing Management System' 因为我是初学者,所以在制作项目时遇到了很多问题。在这里,我已经创建了一个触发器和一个过程,但我不知道如何执行它,我已经为单个产品的总价创建了一个触发器,即 ProdTotal = ProdPrice * ProdQuantity;
。
这意味着每当用户在产品 table 中输入一些数据时,必须执行此触发器,但我不知道如何执行它,同样,我创建了一个程序来计算所有的总价单个客户购买的产品。就像你去超市或任何商店购买物品后,你会收到一张账单,上面有最终的总金额。我什至不确定我的程序代码是对还是错,尽管它已成功创建,但我不确定它是否会给我我想要的确切输出,所以如果你能帮助我,请告诉我,我从不同的网站和许多 youtube 视频中进行了很多研究,但说真的,我不知道如何解决它,所以请帮助我!
代码:
产品table
create table Products
( ProdId number primary key,
ProdNum number not null unique,
ProdName varchar2(15),
ProdPrice int,
ProdQuantity int,
ProdCustId int references Customers,
ProdOrdId int references Orders,
ProdStoreId int references Stores
);
付款table
create table Payments
( PayId int primary key,
PayDate date,
ProdTotal int,
FinalTotal int,
PayOrdId int references orders,
PayProdId int references Products,
PayCustId int references Customers
);
触发码
create trigger PROD_TOTAL
AFTER INSERT ON Products
BEGIN
UPDATE Payments
SET ProdTotal = (SELECT Products.ProdPrice * Products.ProdQuantity FROM Products);
END;
/
程序代码
create procedure FINAL_TOTAL(C IN NUMBER, T OUT NUMBER)
IS
BEGIN
UPDATE Payments
SET FinalTotal = FinalTotal + ProdTotal
WHERE PayCustId = C;
Commit;
SELECT FinalTotal into T FROM Payments WHERE PayCustId = C;
END;
/
在产品中插入语句 table:
insert into Products values(1,1001,'Syrup',30,4,1,1,1);
在付款中插入报表 table:
insert into Payments(PayId, PayDate, PayOrdID, PayProdId, PayCustId)
values(1,date'2020-10-07',1,1,1);
输出:
select * from products;
PRODID PRODNUM PRODNAME PRODPRICE PRODQUANTITY PRODCUSTID
---------- ---------- --------------- ---------- ------------ ----------
PRODORDID PRODSTOREID
---------- -----------
1 1001 Syrup 30 4 1
1 1
select * from Payments;
PAYID PAYDATE PRODTOTAL FINALTOTAL PAYORDID PAYPRODID PAYCUSTID
---------- --------- ---------- ---------- ---------- ---------- ----------
1 07-OCT-20 1 1 1
现在在这里,您可以看到 PRODTOTAL 和 FINALTOTAL 列是空白的,我知道为什么它是空白的,因为我没有输入任何值。我之所以没有在这两列中输入任何值,是因为我想,系统应该在触发器和程序的帮助下自动计算该计算,我什至不能删除触发器和程序,因为它在我们的程序中是强制性的项目使用这两个概念。所以请帮助我!!!
如前所述,首先尝试根据您的要求进行正确的设计。您可以通过正确设计数据库模式来实施许多约束。
尽可能远离触发器和PL/SQL。它最终会迫使您进行更好的设计,并会有所回报。
在将触发器用于业务逻辑之前,请尝试将视图用于可以选择的事物。这就是数据库的用途。
当您“完成”后,测试性能,如果性能不理想,则改进您的架构。如果没有任何帮助,请开始为业务逻辑使用触发器。
我把我正在谈论的观点放在一起 sample。我希望它能帮助你入门。
create table Products (
ProdId number generated always as identity primary key
, ProdName varchar2(20) not null
);
create table Stores (
StoreId number generated always as identity primary key
, StoreName varchar2(20) not null
);
create table Customers (
CustomerId number generated always as identity primary key
, CustomerName varchar2(20) not null
);
create table Prices (
PriceId number generated always as identity primary key
, ProdId number not null
, Price number
, ValidFrom date default on null sysdate
, constraint fk_Prices_Product foreign key (ProdId) references Products (ProdId)
);
create unique index uniq_prices_product_price on Prices (ProdId, ValidFrom);
create table Orders (
OrderId number generated always as identity primary key
, CustomerId number not null
, StoreId number not null
, OrderedAt date default on null sysdate
, constraint fk_Orders_Customer foreign key (CustomerId) references Customers (CustomerId)
, constraint fk_Orders_Store foreign key (StoreId) references Stores (StoreId)
);
create table OrderLines (
OrderLineId number generated always as identity primary key
, OrderId number not null
, ProdId number not null
, ProdQuantity number not null
, constraint fk_OrderLines_Order foreign key (OrderId) references Orders (OrderId)
, constraint fk_OrderLines_Prod foreign key (ProdId) references Products (ProdId)
);
create table Payments (
PaymentId number generated always as identity primary key
, OrderId number not null
, PaidAt date default on null sysdate
, PaidAmount number not null
, constraint fk_Payments_Order foreign key (OrderId) references Orders (OrderId)
);
create view Prices_V as
select
p.*
, coalesce(
lead(p.ValidFrom) over (partition by p.ProdId order by p.ValidFrom)
, to_date('9999', 'YYYY')
) ValidTo
from Prices p;
create view Orders_V as
select
o.*
, (
select sum(ol.ProdQuantity * p.Price)
from OrderLines ol
join Prices_V p on (p.ProdId = ol.ProdId and o.OrderedAt between p.ValidFrom and p.ValidTo)
where o.OrderId = ol.OrderId
) Total
, (
select sum(PaidAmount)
from Payments p
where p.OrderId = o.OrderId
) TotalPaid
from Orders o;
insert into Products(ProdName)
select 'Prod A' from dual union all
select 'Prod B' from dual;
insert into Stores(StoreName) values ('Store A');
insert into Customers(CustomerName)
select 'Customer A' from dual union all
select 'Customer B' from dual;
insert into Prices(ProdId, Price, ValidFrom)
select 1, 10, sysdate - 10 from dual union all
select 1, 12, sysdate - 2 from dual union all
select 1, 14, sysdate + 3 from dual union all
select 2, 100, sysdate - 10 from dual union all
select 2, 90, sysdate - 2 from dual union all
select 2, null, sysdate + 5 from dual;
insert into Orders(CustomerId, StoreId, OrderedAt)
select 1 cid, 1 stoid, sysdate - 5 from dual union all
select 2, 1, sysdate - 5 from dual union all
select 2, 1, sysdate - 1 from dual;
insert into OrderLines(OrderId, ProdId, ProdQuantity)
select 1 ordid, 1 prodid, 3 prodquant from dual union all
select 1, 2, 2 from dual union all
select 2, 2, 10 from dual union all
select 3, 2, 10 from dual;
insert into Payments(OrderId, PaidAmount) values (2, 500);
select * from Prices_V order by ProdId, ValidFrom;
select * from OrderLines order by OrderId, ProdId;
select * from Orders_v order by OrderId;
其中的一些想法:
- 价格存储在单独的 table 中,参考产品并具有有效性,因此产品价格可以随时间变化。价格视图添加了
ValidTo
列,因此更易于使用 - 价格有一个唯一索引,因此我们不能同时为同一产品提供 2 个价格
- 您可以按顺序排列多个项目,这就是为什么存在
Orders
和OrderLines
table 一对多关系的原因 - 在
Order_V
中显示支付总额(使用Payments
上的子查询)并显示总订单值(使用OrderLines
和Prices
上的子查询, 订单日期用于获取正确时期的价格)
根据模式,您将了解哪些可以表示,哪些不能。让它符合您的要求是您的工作:)
现在我谈到了您所说的触发器和过程在您的项目中是强制性的。因此我有一个提议:
- 创建一个允许用户为产品创建新价格的程序。它绝对应该检查有效性不是从过去开始的。然后实施另一个允许更改有效期的日期(也不能在过去结束)。然后,您可以撤销对产品 table 的任何 insert/update 特权,并强制用户使用将包含此业务逻辑的过程。
- 创建一个 table
PricesLog
并在Prices
上触发,这将插入 PriceId、old.Price、new.Price、sysdate 和User
登录任何 inserts/updates 到价格 table.