Zoals reeds voorgesteld, probeer eerst het ontwerp goed te krijgen met betrekking tot uw wensen. U kunt veel beperkingen implementeren door uw databaseschema correct te ontwerpen.
Blijf zo lang mogelijk uit de buurt van triggers en PL/SQL. Het zal je uiteindelijk dwingen om beter te ontwerpen en het zal zijn vruchten afwerpen.
Probeer, voordat u triggers voor bedrijfslogica gebruikt, weergaven te gebruiken voor dingen die kunnen worden geselecteerd. Daar is de database voor.
Wanneer u "klaar" bent, test u de prestaties en verbetert u uw schema als het suboptimaal is. Als niets helpt, begin dan met het gebruiken van triggers voor bedrijfslogica.
Ik heb een voorbeeld samengesteld met uitzicht waar ik het over heb. Ik hoop dat het je op weg kan helpen.
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;
Enkele van de ideeën die erin staan:
- Prijzen worden opgeslagen in een aparte tabel, verwijzen naar het product en zijn geldig, zodat de productprijs in de loop van de tijd kan veranderen. Prijsweergave hebben
ValidTo
kolom toegevoegd zodat het gemakkelijker is om mee te werken - Er is een unieke prijsindex, zodat we niet tegelijkertijd 2 prijzen voor hetzelfde product kunnen hebben
- Je kunt veel artikelen op volgorde hebben, daarom zijn er
Orders
enOrderLines
tabellen in een 1-op-veel relatie - In
Order_V
het totaal betaalde wordt getoond (met behulp van een subquery opPayments
) en de totale bestelwaarden worden weergegeven (met behulp van een subquery opOrderLines
enPrices
, datum van bestelling wordt gebruikt om prijzen uit de juiste periode te krijgen)
Aan de hand van het schema zie je welke dingen je kunt voorstellen en welke niet. Het is jouw taak om het aan je eisen te laten voldoen :)
En nu ben ik op het punt gekomen dat u zegt dat triggers en procedures verplicht zijn in uw project. Daarom heb ik een voorstel:
- Maak een procedure waarmee gebruikers een nieuwe prijs voor een product kunnen maken. Het moet zeker controleren of de geldigheid niet in het verleden begint. Implementeer vervolgens een andere die het mogelijk maakt om de geldige tot nu toe te wijzigen (kan ook niet in het verleden eindigen). U kunt dan alle invoeg-/bijwerkrechten in de tabel Producten intrekken en gebruikers dwingen uw procedures te gebruiken die deze bedrijfslogica bevatten.
- Maak een tabel
PricesLog
en activeer opPrices
die de PriceId, old.Price, new.Price, sysdate enUser
zal invoegen naar het log op eventuele toevoegingen/updates van de prijstabel.