A row-level trigger on table A (i.e. library.borrows) cannot query table A. If you do so, you will get a mutating table exception (unless you can guarantee that you will only ever do single-row inserts with the VALUES clause). So that would not be considered a good development practice in Oracle.
The most logical way to implement this sort of requirement would not be via a trigger. Instead, if your application calls a stored procedure API, you would have a stored procedure (i.e. CHECK_OUT) that first queries the table to determine how many books an individual has checked out and inserts the row into the BORROWS table only if the patron is below his or her limit.
A second approach is to store the number of items checked out in a separate table. If you had a PATRONS table with a NUM_CHECKED_OUT column and your BORROWS table had a PATRON_ID to indicate who had borrowed the book, your trigger could do something like
CREATE OR REPLACE TRIGGER CheckBorrowsTable
BEFORE INSERT ON library.borrows
FOR EACH ROW
BEGIN
UPDATE patrons p
SET p.num_checked_out = p.num_checked_out + 1
WHERE p.patron_id = :new.patron_id
END;
along with a CHECK constraint on the PATRONS table to ensure that NUM_CHECKED_OUT never exceeds 3.
Barring that, it is possible, though rather cumbersome, to work around the mutating table error with the "three trigger solution".
- A BEFORE INSERT statement level
trigger clears out a collection that
you have created in a package.
- A BEFORE INSERT row level trigger
writes the primary key (or ROWID) of
the row being modified into the
collection.
- An AFTER INSERT statement
level trigger reads the data from
the collection, queries the table,
and determines if any of the inserts
have violated the business rule. If
they did, throw an exception.
As you might imagine, however, the three trigger solution involves a fair number of moving pieces so it's not particularly advisable.
You can also implement this sort of thing with a fast refreshable materialized view, but I don't believe that is an option in the express edition of the database (though I could be wrong on that).