0% found this document useful (0 votes)
247 views

Database Management Systems Raghu Ramakrishnan 185 192

This document discusses complex integrity constraints and triggers in SQL. It describes how to specify constraints over single tables and multiple tables using CHECK constraints and assertions. Triggers allow stored procedures to be automatically executed in response to data changes, and are useful for maintaining derived data or performing integrity checks. Triggers have an event that activates them, an optional condition, and an action that executes if the condition is met.

Uploaded by

mani111111
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
247 views

Database Management Systems Raghu Ramakrishnan 185 192

This document discusses complex integrity constraints and triggers in SQL. It describes how to specify constraints over single tables and multiple tables using CHECK constraints and assertions. Triggers allow stored procedures to be automatically executed in response to data changes, and are useful for maintaining derived data or performing integrity checks. Triggers have an event that activates them, an optional condition, and an action that executes if the condition is met.

Uploaded by

mani111111
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

SQL: Queries, Programming, Triggers

5.11 COMPLEX INTEGRITY CONSTRAINTS IN SQL-92 *

In this section we discuss the specification of complex integrity constraints in SQL-92,


utilizing the full power of SQL query constructs. The features discussed in this section
complement the integrity constraint features of SQL presented in Chapter 3.

5.11.1 Constraints over a Single Table

We can specify complex constraints over a single table using table constraints, which
have the form CHECK conditional-expression. For example, to ensure that rating must
be an integer in the range 1 to 10, we could use:

CREATE TABLE Sailors ( sid INTEGER,


sname CHAR(10),
rating INTEGER,
age REAL,
PRIMARY KEY (sid),
CHECK ( rating >= 1 AND rating <= 10 ))

To enforce the constraint that Interlake boats cannot be reserved, we could use:
CHAPTER 3

CREATE TABLE Reserves ( sid INTEGER,


bid INTEGER,
day DATE,
FOREIGN KEY (sid) REFERENCES Sailors
FOREIGN KEY (bid) REFERENCES Boats
CONSTRAINT noInterlakeRes
CHECK ( ‘Interlake’ <>
( SELECT B.bname
FROM Boats B
WHERE B.bid = Reserves.bid )))

When a row is inserted into Reserves or an existing row is modified, the conditional
expression in the CHECK constraint is evaluated. If it evaluates to false, the command
is rejected.

5.11.2 Domain Constraints

A user can define a new domain using the CREATE DOMAIN statement, which makes use
of CHECK constraints.

CREATE DOMAIN ratingval INTEGER DEFAULT 0


CHECK ( VALUE >= 1 AND VALUE <= 10 )

INTEGER is the base type for the domain ratingval, and every ratingval value
must be of this type. Values in ratingval are further restricted by using a CHECK
constraint; in defining this constraint, we use the keyword VALUE to refer to a value
in the domain. By using this facility, we can constrain the values that belong to a
domain using the full power of SQL queries. Once a domain is defined, the name of
the domain can be used to restrict column values in a table; we can use the following
line in a schema declaration, for example:

rating ratingval

The optional DEFAULT keyword is used to associate a default value with a domain. If
the domain ratingval is used for a column in some relation, and no value is entered
for this column in an inserted tuple, the default value 0 associated with ratingval is
used. (If a default value is specified for the column as part of the table definition, this
takes precedence over the default value associated with the domain.) This feature can
be used to minimize data entry errors; common default values are automatically filled
in rather than being typed in.

SQL-92’s support for the concept of a domain is limited in an important respect.


For example, we can define two domains called Sailorid and Boatclass, each using
SQL: Queries, Programming, Triggers

INTEGER as a base type. The intent is to force a comparison of a Sailorid value with a
Boatclass value to always fail (since they are drawn from different domains); however,
since they both have the same base type, INTEGER, the comparison will succeed in SQL-
92. This problem is addressed through the introduction of distinct types in SQL:1999
(see Section 3.4).

5.11.3 Assertions: ICs over Several Tables

Table constraints are associated with a single table, although the conditional expression
in the CHECK clause can refer to other tables. Table constraints are required to hold
only if the associated table is nonempty. Thus, when a constraint involves two or more
tables, the table constraint mechanism is sometimes cumbersome and not quite what
is desired. To cover such situations, SQL supports the creation of assertions, which
are constraints not associated with any one table.

As an example, suppose that we wish to enforce the constraint that the number of
boats plus the number of sailors should be less than 100. (This condition might be
required, say, to qualify as a ‘small’ sailing club.) We could try the following table
constraint:

CREATE TABLE Sailors ( sid INTEGER,


sname CHAR(10),
rating INTEGER,
age REAL,
PRIMARY KEY (sid),
CHECK ( rating >= 1 AND rating <= 10)
CHECK ( ( SELECT COUNT (S.sid) FROM Sailors S )
+ ( SELECT COUNT (B.bid) FROM Boats B )
< 100 ))

This solution suffers from two drawbacks. It is associated with Sailors, although it
involves Boats in a completely symmetric way. More important, if the Sailors table is
empty, this constraint is defined (as per the semantics of table constraints) to always
hold, even if we have more than 100 rows in Boats! We could extend this constraint
specification to check that Sailors is nonempty, but this approach becomes very cum-
bersome. The best solution is to create an assertion, as follows:

CREATE ASSERTION smallClub


CHECK (( SELECT COUNT (S.sid) FROM Sailors S )
+ ( SELECT COUNT (B.bid) FROM Boats B)
< 100 )
CHAPTER 3

5.12 TRIGGERS AND ACTIVE DATABASES

A trigger is a procedure that is automatically invoked by the DBMS in response to


specified changes to the database, and is typically specified by the DBA. A database
that has a set of associated triggers is called an active database. A trigger description
contains three parts:

Event: A change to the database that activates the trigger.

Condition: A query or test that is run when the trigger is activated.

Action: A procedure that is executed when the trigger is activated and its con-
dition is true.

A trigger can be thought of as a ‘daemon’ that monitors a database, and is executed


when the database is modified in a way that matches the event specification. An
insert, delete or update statement could activate a trigger, regardless of which user
or application invoked the activating statement; users may not even be aware that a
trigger was executed as a side effect of their program.

A condition in a trigger can be a true/false statement (e.g., all employee salaries are
less than $100,000) or a query. A query is interpreted as true if the answer set is
nonempty, and false if the query has no answers. If the condition part evaluates to
true, the action associated with the trigger is executed.

A trigger action can examine the answers to the query in the condition part of the
trigger, refer to old and new values of tuples modified by the statement activating
the trigger, execute new queries, and make changes to the database. In fact, an
action can even execute a series of data-definition commands (e.g., create new tables,
change authorizations) and transaction-oriented commands (e.g., commit), or call host-
language procedures.

An important issue is when the action part of a trigger executes in relation to the
statement that activated the trigger. For example, a statement that inserts records
into the Students table may activate a trigger that is used to maintain statistics on how
many students younger than 18 are inserted at a time by a typical insert statement.
Depending on exactly what the trigger does, we may want its action to execute before
changes are made to the Students table, or after: a trigger that initializes a variable
used to count the number of qualifying insertions should be executed before, and a
trigger that executes once per qualifying inserted record and increments the variable
should be executed after each record is inserted (because we may want to examine the
values in the new record to determine the action).
SQL: Queries, Programming, Triggers

5.12.1 Examples of Triggers in SQL

The examples shown in Figure 5.19, written using Oracle 7 Server syntax for defining
triggers, illustrate the basic concepts behind triggers. (The SQL:1999 syntax for these
triggers is similar; we will see an example using SQL:1999 syntax shortly.) The trigger
called init count initializes a counter variable before every execution of an INSERT
statement that adds tuples to the Students relation. The trigger called incr count
increments the counter for each inserted tuple that satisfies the condition age < 18.

CREATE TRIGGER init count BEFORE INSERT ON Students /* Event */


DECLARE
count INTEGER;
BEGIN /* Action */
count := 0;
END

CREATE TRIGGER incr count AFTER INSERT ON Students /* Event */


WHEN (new.age < 18) /* Condition; ‘new’ is just-inserted tuple */
FOR EACH ROW
BEGIN /* Action; a procedure in Oracle’s PL/SQL syntax */
count := count + 1;
END

Figure 5.19 Examples Illustrating Triggers

One of the example triggers in Figure 5.19 executes before the activating statement,
and the other example executes after. A trigger can also be scheduled to execute
instead of the activating statement, or in deferred fashion, at the end of the transaction
containing the activating statement, or in asynchronous fashion, as part of a separate
transaction.

The example in Figure 5.19 illustrates another point about trigger execution: A user
must be able to specify whether a trigger is to be executed once per modified record
or once per activating statement. If the action depends on individual changed records,
for example, we have to examine the age field of the inserted Students record to decide
whether to increment the count, the triggering event should be defined to occur for
each modified record; the FOR EACH ROW clause is used to do this. Such a trigger is
called a row-level trigger. On the other hand, the init count trigger is executed just
once per INSERT statement, regardless of the number of records inserted, because we
have omitted the FOR EACH ROW phrase. Such a trigger is called a statement-level
trigger.
CHAPTER 3

In Figure 5.19, the keyword new refers to the newly inserted tuple. If an existing tuple
were modified, the keywords old and new could be used to refer to the values before
and after the modification. The SQL:1999 draft also allows the action part of a trigger
to refer to the set of changed records, rather than just one changed record at a time.
For example, it would be useful to be able to refer to the set of inserted Students
records in a trigger that executes once after the INSERT statement; we could count the
number of inserted records with age < 18 through an SQL query over this set. Such
a trigger is shown in Figure 5.20 and is an alternative to the triggers shown in Figure
5.19.

The definition in Figure 5.20 uses the syntax of the SQL:1999 draft, in order to il-
lustrate the similarities and differences with respect to the syntax used in a typical
current DBMS. The keyword clause NEW TABLE enables us to give a table name (In-
sertedTuples) to the set of newly inserted tuples. The FOR EACH STATEMENT clause
specifies a statement-level trigger and can be omitted because it is the default. This
definition does not have a WHEN clause; if such a clause is included, it follows the FOR
EACH STATEMENT clause, just before the action specification.

The trigger is evaluated once for each SQL statement that inserts tuples into Students,
and inserts a single tuple into a table that contains statistics on modifications to
database tables. The first two fields of the tuple contain constants (identifying the
modified table, Students, and the kind of modifying statement, an INSERT), and the
third field is the number of inserted Students tuples with age < 18. (The trigger in
Figure 5.19 only computes the count; an additional trigger is required to insert the
appropriate tuple into the statistics table.)

CREATE TRIGGER set count AFTER INSERT ON Students /* Event */


REFERENCING NEW TABLE AS InsertedTuples
FOR EACH STATEMENT
INSERT /* Action */
INTO StatisticsTable(ModifiedTable, ModificationType, Count)
SELECT ‘Students’, ‘Insert’, COUNT *
FROM InsertedTuples I
WHERE I.age < 18

Figure 5.20 Set-Oriented Trigger

5.13 DESIGNING ACTIVE DATABASES

Triggers offer a powerful mechanism for dealing with changes to a database, but they
must be used with caution. The effect of a collection of triggers can be very complex,
SQL: Queries, Programming, Triggers

and maintaining an active database can become very difficult. Often, a judicious use
of integrity constraints can replace the use of triggers.

5.13.1 Why Triggers Can Be Hard to Understand

In an active database system, when the DBMS is about to execute a statement that
modifies the database, it checks whether some trigger is activated by the statement. If
so, the DBMS processes the trigger by evaluating its condition part, and then (if the
condition evaluates to true) executing its action part.

If a statement activates more than one trigger, the DBMS typically processes all of
them, in some arbitrary order. An important point is that the execution of the action
part of a trigger could in turn activate another trigger. In particular, the execution of
the action part of a trigger could again activate the same trigger; such triggers are called
recursive triggers. The potential for such chain activations, and the unpredictable
order in which a DBMS processes activated triggers, can make it difficult to understand
the effect of a collection of triggers.

5.13.2 Constraints versus Triggers

A common use of triggers is to maintain database consistency, and in such cases,


we should always consider whether using an integrity constraint (e.g., a foreign key
constraint) will achieve the same goals. The meaning of a constraint is not defined
operationally, unlike the effect of a trigger. This property makes a constraint easier
to understand, and also gives the DBMS more opportunities to optimize execution.
A constraint also prevents the data from being made inconsistent by any kind of
statement, whereas a trigger is activated by a specific kind of statement (e.g., an insert
or delete statement). Again, this restriction makes a constraint easier to understand.

On the other hand, triggers allow us to maintain database integrity in more flexible
ways, as the following examples illustrate.

Suppose that we have a table called Orders with fields itemid, quantity, customerid,
and unitprice. When a customer places an order, the first three field values are
filled in by the user (in this example, a sales clerk). The fourth field’s value can
be obtained from a table called Items, but it is important to include it in the
Orders table to have a complete record of the order, in case the price of the item
is subsequently changed. We can define a trigger to look up this value and include
it in the fourth field of a newly inserted record. In addition to reducing the number
of fields that the clerk has to type in, this trigger eliminates the possibility of an
entry error leading to an inconsistent price in the Orders table.
CHAPTER 3

Continuing with the above example, we may want to perform some additional
actions when an order is received. For example, if the purchase is being charged
to a credit line issued by the company, we may want to check whether the total
cost of the purchase is within the current credit limit. We can use a trigger to do
the check; indeed, we can even use a CHECK constraint. Using a trigger, however,
allows us to implement more sophisticated policies for dealing with purchases that
exceed a credit limit. For instance, we may allow purchases that exceed the limit
by no more than 10% if the customer has dealt with the company for at least a
year, and add the customer to a table of candidates for credit limit increases.

5.13.3 Other Uses of Triggers

Many potential uses of triggers go beyond integrity maintenance. Triggers can alert
users to unusual events (as reflected in updates to the database). For example, we
may want to check whether a customer placing an order has made enough purchases
in the past month to qualify for an additional discount; if so, the sales clerk must be
informed so that he can tell the customer, and possibly generate additional sales! We
can relay this information by using a trigger that checks recent purchases and prints a
message if the customer qualifies for the discount.

Triggers can generate a log of events to support auditing and security checks. For
example, each time a customer places an order, we can create a record with the cus-
tomer’s id and current credit limit, and insert this record in a customer history table.
Subsequent analysis of this table might suggest candidates for an increased credit limit
(e.g., customers who have never failed to pay a bill on time and who have come within
10% of their credit limit at least three times in the last month).

As the examples in Section 5.12 illustrate, we can use triggers to gather statistics on
table accesses and modifications. Some database systems even use triggers internally
as the basis for managing replicas of relations (Section 21.10.1). Our list of potential
uses of triggers is not exhaustive; for example, triggers have also been considered for
workflow management and enforcing business rules.

5.14 POINTS TO REVIEW

A basic SQL query has a SELECT, a FROM, and a WHERE clause. The query answer
is a multiset of tuples. Duplicates in the query result can be removed by using
DISTINCT in the SELECT clause. Relation names in the WHERE clause can be fol-
lowed by a range variable. The output can involve arithmetic or string expressions
over column names and constants and the output columns can be renamed using
AS. SQL provides string pattern matching capabilities through the LIKE operator.
(Section 5.2)

You might also like