Using Triggers to Provide Default Values
Using Triggers to Provide Default Values
Earlier in this chapter, you learned to use the SQL DEFAULT keyword to provide initial column values. DEFAULT works only for simple expressions, however. If the computation of a default value requires complicated logic, then an INSERT trigger must be used instead.
For example, suppose that there is a policy at View Ridge Gallery to set the value of AskingPrice equal either to twice the AcquisitionPrice or to the AcquisitionPrice plus the average net gain for sales of this art in the past, whichever is greater. The AFTER trigger in Figure 7-26 implements this policy. Note that the code in Figure 7-26, although resembling Oracle PL/SQL, is generic pseudocode. You will learn how to write specific code for SQL Server, Oracle Database, and MySQL in Chapters 10, 10A, and 10B, respectively.
After declaring program variables, the trigger reads the TRANS table to find out how many TRANS rows exist for this work. Because this is an AFTER trigger, the new TRANS row for the work will have already been inserted. Thus, the count will be one if this is the first time the work has been in the gallery. If so, the new value of SalesPrice is set to twice the AcquisitionPrice.
If the user variable rowCount is greater than one, then the work has been in the gallery before. To compute the average gain for this work, the trigger uses the ArtistWorkNetView described on page 284 to compute SUM(NetProfit) for this work. The sum is placed in the variable sumNetProfit. Notice that the WHERE clause limits the rows to be used in the view to this particular work. The average is then computed by dividing this sum by rowCount minus one.
You may be wondering, why not use AVG(NetProfit) in the SQL statement? The answer is that the default SQL average function would have counted the new row in the computa- tion of the average. We do not want that row to be included, so we subtract one from rowCount when the average is computed. Once the value of avgNetProfit has been computed, it is compared with twice the AcquisitionPrice; the larger result is used for the new value of AskingPrice.
Chapter 7 SQL for Database Construction and Application Processing
Figure 7-26
Trigger Code to Insert
Using Triggers to Enforce Data Constraints
a Default Value
A second purpose of triggers is to enforce data constraints. Although SQL CHECK constraints can be used to enforce domain, range, and intrarelation constraints, no DBMS vendor has implemented the SQL-92 features for interrelation CHECK constraints. Consequently, such constraints are implemented in triggers.
Suppose, for example, that the gallery has a special interest in Mexican painters and never discounts the price of their works. Thus, the SalesPrice of a work must always
be at least the AskingPrice. To enforce this rule, the gallery database has an insert and update trigger on TRANS that checks to see if the work is by a Mexican painter. If so, the SalesPrice is checked against the AskingPrice. If it is less than the AskingPrice, the SalesPrice is reset to the AskingPrice. This, of course, must happen when the art work is actually being sold, and the customer charged the full amount! This is not a postsale accounting adjustment.
Part 3 Database Implementation
Figure 7-27
Figure 7-27 shows generic trigger code that implements this rule. This trigger will be fired after any insert or update on a TRANS row. The trigger first checks to determine if the work is
Trigger Code to Enforce an
by a Mexican artist. If not, the trigger is exited. Otherwise, the SalesPrice is checked against
Interrelation Data Constraint
the AskingPrice; if it is less than the AskingPrice, the SalesPrice is set equal to the AskingPrice. This trigger will be called recursively; the update statement in the trigger will cause an update on TRANS, which will cause the trigger to be called again. The second time, however, the SalesPrice will be equal to the AskingPrice, no more updates will be made, and the recursion will stop.