sql >> Base de Datos >  >> RDS >> Oracle

Cómo ejecutar el disparador y el procedimiento en Oracle

Como ya se propuso, primero intente obtener el diseño correcto con respecto a sus requisitos. Puede implementar muchas restricciones simplemente diseñando correctamente el esquema de su base de datos.

Manténgase alejado de los disparadores y PL/SQL durante el mayor tiempo posible. Te obligará a diseñar mejor al final y valdrá la pena.

Antes de usar disparadores para la lógica empresarial, intente usar vistas para las cosas que se pueden seleccionar. Para eso está la base de datos.

Cuando haya "terminado", pruebe el rendimiento y, si no es óptimo, mejore su esquema. Si nada ayuda, comience a usar activadores para la lógica empresarial.

Reuní una muestra con las vistas de las que estoy hablando. Espero que pueda ayudarte a empezar.

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;

Algunas de las ideas allí:

  1. Los precios se almacenan en tablas separadas, hacen referencia al producto y tienen validez para que el precio del producto pueda cambiar con el tiempo. La vista de precio tiene ValidTo columna agregada para que sea más fácil trabajar con ella
  2. Existe un índice único de precios, por lo que no podemos tener 2 precios para el mismo producto al mismo tiempo
  3. Puedes tener muchos artículos en orden, por eso hay Orders y OrderLines tablas en relación de 1 a muchos
  4. En Order_V se muestra el total pagado (utilizando una subconsulta en Payments ) y se muestran los valores totales del pedido (utilizando una subconsulta en OrderLines y Prices , la fecha del pedido se usa para obtener los precios del período correcto)

A partir del esquema verás qué cosas puedes representar y cuáles no. Es tu trabajo hacer que coincida con tus requisitos :)

Y ahora llegué al punto en que dices que los disparadores y los procedimientos son obligatorios en tu proyecto. Por lo tanto, tengo una propuesta:

  1. Cree un procedimiento que permita a los usuarios crear un nuevo precio para un producto. Definitivamente debe verificar que la validez no comience en el pasado. Luego implemente otro que permita cambiar la fecha válida hasta (tampoco puede terminar en el pasado). Puede revocar cualquier privilegio de inserción/actualización en la tabla Productos y obligar a los usuarios a utilizar sus procedimientos que contendrán esta lógica empresarial.
  2. Cree una tabla PricesLog y desencadenar en Prices que insertará PriceId, old.Price, new.Price, sysdate y User al registro de cualquier inserción/actualización de la tabla de precios.