如何在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;

其中的一些想法:

  1. 价格存储在单独的 table 中,参考产品并具有有效性,因此产品价格可以随时间变化。价格视图添加了 ValidTo 列,因此更易于使用
  2. 价格有一个唯一索引,因此我们不能同时为同一产品提供 2 个价格
  3. 您可以按顺序排列多个项目,这就是为什么存在 OrdersOrderLines table 一对多关系的原因
  4. Order_V 中显示支付总额(使用 Payments 上的子查询)并显示总订单值(使用 OrderLinesPrices 上的子查询, 订单日期用于获取正确时期的价格)

根据模式,您将了解哪些可以表示,哪些不能。让它符合您的要求是您的工作:)

现在我谈到了您所说的触发器和过程在您的项目中是强制性的。因此我有一个提议:

  1. 创建一个允许用户为产品创建新价格的程序。它绝对应该检查有效性不是从过去开始的。然后实施另一个允许更改有效期的日期(也不能在过去结束)。然后,您可以撤销对产品 table 的任何 insert/update 特权,并强制用户使用将包含此业务逻辑的过程。
  2. 创建一个 table PricesLog 并在 Prices 上触发,这将插入 PriceId、old.Price、new.Price、sysdate 和 User登录任何 inserts/updates 到价格 table.