Như đã đề xuất, trước tiên hãy cố gắng thiết kế phù hợp với yêu cầu của bạn. Bạn có thể triển khai nhiều ràng buộc chỉ bằng cách thiết kế đúng lược đồ cơ sở dữ liệu của mình.
Tránh xa các trình kích hoạt và PL / SQL càng lâu càng tốt. Cuối cùng, nó sẽ buộc bạn phải thiết kế tốt hơn và sẽ được đền đáp.
Trước khi sử dụng trình kích hoạt cho logic nghiệp vụ, hãy thử sử dụng các chế độ xem cho những thứ có thể được chọn. Đó là những gì cơ sở dữ liệu dành cho.
Khi bạn "hoàn thành", hãy kiểm tra hiệu suất và nếu nó chưa tối ưu, hãy cải thiện giản đồ của bạn. Nếu không có gì hữu ích, hãy bắt đầu sử dụng trình kích hoạt cho logic nghiệp vụ.
Tôi đã tổng hợp một mẫu với quan điểm mà tôi đang nói đến. Tôi hy vọng nó có thể giúp bạn bắt đầu.
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;
Một số ý tưởng trong đó:
- Giá được lưu trong bảng riêng, tham khảo sản phẩm và có giá trị để giá sản phẩm có thể thay đổi theo thời gian. Chế độ xem giá có
ValidTo
đã thêm cột để dễ làm việc hơn - Có một chỉ số duy nhất về Giá để chúng tôi không thể có 2 mức giá cho cùng một sản phẩm cùng một lúc
- Bạn có thể có nhiều mặt hàng để đặt hàng, vì vậy đó là lý do tại sao có
Orders
vàOrderLines
các bảng trong mối quan hệ 1-nhiều - Trong
Order_V
tổng số tiền đã thanh toán được hiển thị (sử dụng truy vấn con trênPayments
) và tổng giá trị đơn hàng được hiển thị (sử dụng truy vấn con trênOrderLines
vàPrices
, ngày đặt hàng được sử dụng để tính giá theo khoảng thời gian chính xác)
Dựa trên lược đồ, bạn sẽ biết được những thứ bạn có thể đại diện và những thứ bạn không thể đại diện. Công việc của bạn là làm cho nó phù hợp với yêu cầu của bạn :)
Và bây giờ tôi đã đi đến điểm bạn nói rằng các trình kích hoạt và thủ tục là bắt buộc trong dự án của bạn. Do đó tôi có một đề xuất:
- Tạo quy trình cho phép người dùng tạo giá mới cho sản phẩm. Nó chắc chắn sẽ kiểm tra xem hiệu lực không bắt đầu trong quá khứ. Sau đó, triển khai một cái khác cho phép thay đổi giá trị hợp lệ thành ngày (cũng không thể kết thúc trong quá khứ). Bạn không thể hủy bỏ bất kỳ đặc quyền chèn / cập nhật nào trên bảng Sản phẩm và buộc người dùng sử dụng các quy trình của bạn có chứa logic nghiệp vụ này.
- Tạo bảng
PricesLog
và kích hoạtPrices
điều đó sẽ chèn PriceId, old.Price, new.Price, sysdate vàUser
vào nhật ký về bất kỳ lần chèn / cập nhật nào đối với bảng giá cả.