Data Model Assumptions:
I am assuming you will register transactions by changing the data in the SELL
table through INSERT
DML SQL operations. This is also supported by your set up of a DML trigger on SELL
to pass its changes as SALES information to the BOOK
table. This is workable.
By accident, I tried setting up the trigger a little differently and I'd like to suggest a different approach:
Consider possibly working in the opposite direction: Change book quantities directly on the BOOK
table, so a single purchase of book_id = 5 would handle queries that could:
UPDATE book SET amount = amount -1
WHERE id = 5; COMMIT;
Restocking would mean increasing the quantity of available books
by incrementing the AMOUNT
value instead.
There are a few additional changes that might tighten up this two-table design and protect the integrity of the data within them for the longer term:
CREATE TABLE book (
id number(3) not null,
name varchar(20),
author varchar(12),
amount number(3) not null,
CONSTRAINT book_pk PRIMARY KEY(id)
);
ALTER TABLE book
ADD CONSTRAINT book_amt_ck CHECK (amount > 0);
ALTER TABLE book
ENABLE CONSTRAINT book_amt_ck;
To prevent negative book amount (quantity) values, a TABLE CHECK CONSTRAINT would prevent the entry of values by means of arithmetic errors in DML operations such as:
UPDATE book SET amount := amount - 1
In the example above, there is no control over decrementing the book inventory even if the quantity on hand has reached 0. Check out a few references on TABLE CHECK CONSTRAINTS to get a better understanding of what it can do for specific design situations.
Here are some design suggestions for the trigger:
Changes in book quantities should be the only triggering data element that affects the
SELL
table.The trigger should account for changes in book quantities > 1.
CREATE OR REPLACE TRIGGER orders_after_update AFTER UPDATE ON book FOR EACH ROW DECLARE v_amount number; BEGIN IF (:new.amount < :old.amount ) THEN FOR v_amount in 1 .. (:old.amount - :new.amount) LOOP INSERT INTO sell (id, date, book_id) VALUES (sell_seq.nextval, sysdate, :new.id); COMMIT; END LOOP; END IF; END;
For more information on triggers and their design, check a few instances to get a better understanding of how they are designed and set up.
CREATE SEQUENCE sell_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 20;
We needed a sequence to populate the primary key/index of the SELL
table. Oracle Sequences are useful for this purpose.
By watching the table changes with a trigger on the BOOK
table, you can use the built in references which already exist when a table trigger fires. For example, BOOK.ID
does not require an additional query because a trigger automatically is made aware of the beginning and ending value of each trigger monitored record.
Some useful discussions on triggers are discussed in more detail through an Internet search.
Setting Up a Foreign Key Relationship
Although the trigger will probably keep this relation clean, a Foreign Key relation between elements BOOK.ID
and SELL.BOOK_ID
would be good, otherwise queries on Sales transactions may yield book sales without any descriptive production information. The following is a reference on Foreign Keys and their use.
CREATE TABLE sell (
id number(3) not null,
date varchar(20),
book_id number(3)
);
ALTER TABLE table_name
ADD CONSTRAINT sell_fk
FOREIGN KEY (book_id)
REFERENCES book(id);