すでに提案されているように、最初に要件に応じて設計を正しくするようにしてください。データベーススキーマを正しく設計するだけで、多くの制約を実装できます。
トリガーやPL/SQLからできるだけ長く離れてください。最終的にはより良い設計を余儀なくされ、成果が得られます。
ビジネスロジックにトリガーを使用する前に、選択可能なものにビューを使用してみてください。それがデータベースの目的です。
「完了」したら、パフォーマンスをテストし、最適でない場合はスキーマを改善します。何も役に立たない場合は、ビジネスロジックのトリガーの使用を開始します。
サンプル をまとめました。 私が話している意見で。始められることを願っています。
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;
そこにあるアイデアのいくつか:
- 価格は別のテーブルに保存され、製品を参照し、有効性があるため、製品の価格は時間の経過とともに変化する可能性があります。価格ビューには
ValidTo
があります 作業しやすいように列が追加されました - 価格には独自のインデックスがあるため、同じ商品に対して同時に2つの価格を設定することはできません。
- 多くのアイテムを順番に並べることができるため、
Orders
があります。 およびOrderLines
1対多の関係にあるテーブル -
Order_V
内 支払われた合計が表示されます(Payments
のサブクエリを使用) )、合計注文値が表示されます(OrderLines
のサブクエリを使用) およびPrices
、注文日は正しい期間から価格を取得するために使用されます)
スキーマに基づいて、表現できるものとできないものを選択します。要件に一致させるのはあなたの仕事です:)
そして今、私はあなたがあなたのプロジェクトでトリガーと手順が必須であるとあなたが言うところまで来ました。したがって、私は提案があります:
- ユーザーが製品の新しい価格を作成できるようにする手順を作成します。有効性が過去に始まっていないことを確実にチェックする必要があります。次に、有効な日付を変更できる別のものを実装します(過去に終了することもできません)。その後、Productsテーブルに対する挿入/更新権限を取り消して、このビジネスロジックを含むプロシージャをユーザーに使用させることができます。
- テーブルを作成する
PricesLog
Prices
でトリガーします これにより、PriceId、old.Price、new.Price、sysdate、およびUser
が挿入されます。 価格表への挿入/更新に関するログへ。