Вы находитесь на странице: 1из 13

5 Integrity Constraints and Triggers

5.1 Integrity Constraints


In Section 1 we have discussed three types of integrity constraints: not null constraints, primary keys, and uni ue constraints. In this section we introduce two more types of constraints that can !e specified within the create ta!le statement: check constraints "to restrict possi!le attri!ute values#, and foreign key constraints "to specify interdependencies !etween relations#. 5.1.1 Check Constraints $ften columns in a ta!le must have values that are within a certain range or that satisfy certain conditions. Check constraints allow users to restrict possi!le attri!ute values for a column to admissi!le ones. They can !e specified as column constraints or ta!le constraints. The synta% for a check constraint is &constraint 'name() check"'condition(# If a check constraint is specified as a column constraint, the condition can only refer that column. *%ample: The name of an employee must consist of upper case letters only+ the minimum salary of an employee is 5,,+ department num!ers must range !etween 1, and 1,,: create ta!le *-. "..., */0-* varchar1"2,# constraint check name check"*/0-* 3 upper"*/0-*# #, S04 num!er"5,1# constraint check sal check"S04 (3 5,,#, 5*.T/$ num!er"2# constraint check deptno check"5*.T/$ !etween 1, and 1,,# #+ If a check constraint is specified as a ta!le constraint, 'condition( can refer to all columns of the ta!le. /ote that only simple conditions are allowed. 6or e%ample, it is not allowed to refer to columns of other ta!les or to formulate ueries as check conditions. 6urthermore, the functions sysdate and user cannot !e used in a condition. In principle, thus only simple attri!ute comparisons and logical connectives such as and, or, and not are allowed. 0 check condition, however, can include a not null constraint: S04 num!er"5,1# constraint check sal check"S04 is not null and S04 (3 5,,#, 7ithout the not null condition, the value null for the attri!ute S04 would not cause a violation

of the constraint. *%ample: 0t least two persons must participate in a pro8ect, and the pro8ect9s start date must !e !efore the pro8ect9s end date: :; create ta!le .<$=*CT "..., .*<S$/S num!er"5# constraint check pers check ".*<S$/S ( 1#, ..., constraint dates ok check".*/5 ( .ST0<T# #+ In this ta!le definition, check pers is a column constraint and dates ok is a ta!le constraint. The data!ase system automatically checks the specified conditions each time a data!ase modification is performed on this relation. 6or e%ample, the insertion insert into *-. values">???,9SC$TT9,9C4*<@9,>;?A,921B$CTB?:9,:5,,1,#+ causes a constraint violation $<0B,11?,: check constraint "CC*C@ S04# violated and the insertion is re8ected. 5.1.1 6oreign @ey Constraints 0 foreign key constraint "or referential integrity constraint# can !e specified as a column constraint or as a ta!le constraint: &constraint 'name() &foreign key "'column"s#(#) references 'ta!le(&"'column"s#(#) &on delete cascade) This constraint specifies a column or a list of columns as a foreign key of the referencing ta!le. The referencing ta!le is called the childBta!le, and the referenced ta!le is called the parentBta!le. In other words, one cannot define a referential integrity constraint that refers to a ta!le < !efore that ta!le < has !een created. The clause foreign key has to !e used in addition to the clause references if the foreign key includes more than one column. In this case, the constraint has to !e specified as a ta!le constraint. The clause references defines which columns of the parentB ta!le are referenced. If only the name of the parentBta!le is given, the list of attri!utes that !uild the primary key of that ta!le is assumed. *%ample: *ach employee in the ta!le *-. must work in a department that is contained in the ta!le 5*.T: create ta!le *-. " *-./$ num!er":# constraint pk emp primary key, ..., 5*.T/$ num!er"2# constraint fk deptno references 5*.T"5*.T/$# #+

The column 5*.T/$ of the ta!le *-. "childBta!le# !uilds the foreign key and references the primary key of the ta!le 5*.T "parentBta!le#. The relationship !etween these two ta!les is illustrated in 6igure 1. Since in this ta!le definition the referential integrity constraint includes :> only one column, the clause foreign key is not used. It is very important that a foreign key must refer to the complete primary key of a parentBta!le, not only a su!set of the attri!utes that !uild the primary key D
10 10 20 20 30 10 20 30 40 DEPTNO DEPTNO EMP (Child-Table) DEPT (Parent-Table) ... ... ... ... ... ... ... ... ... ... ... primary key foreign key references

6igure 1: 6oreign @ey Constraint !etween the Ta!les *-. and 5*.T In order to satisfy a foreign key constraint, each row in the childBta!le has to satisfy one of the following two conditions: E the attri!ute value "list of attri!ute values# of the foreign key must appear as a primary key value in the parentBta!le, or E the attri!ute value of the foreign key is null "in case of a composite foreign key, at least one attri!ute value of the foreign key is null # 0ccording to the a!ove definition for the ta!le *-., an employee must not necessarily work in a department, i.e., for the attri!ute 5*.T/$ the value null is admissi!le. *%ample: *ach pro8ect manager must !e an employee: create ta!le .<$=*CT

" ./$ num!er"2# constraint pr8 pk primary key, .-F< num!er":# not null constraint fk pmgr references *-., . . . #+ Gecause only the name of the parentBta!le is given "5*.T#, the primary key of this relation is assumed. 0 foreign key constraint may also refer to the same ta!le, i.e., parentBta!le and childBta!le are identical. *%ample: *ach manager must !e an employee: create ta!le *-. " *-./$ num!er":# constraint emp pk primary key, ... -F< num!er":# not null constraint fk mgr references *-., ... #+ :A 5.1.2 -ore a!out ColumnB and Ta!le Constraints If a constraint is defined within the create ta!le command or added using the alter ta!le command "compare Section 1.5.5#, the constraint is automatically ena!led. 0 constraint can !e disa!led using the command alter ta!le 'ta!le( disa!le constraint 'name( H primary key H uni ue&'column"s#() &cascade)+ To disa!le a primary key, one must disa!le all foreign key constraints that depend on this primary key. The clause cascade automatically disa!les foreign key constraints that depend on the "disa!led# primary key. *%ample: 5isa!le the primary key of the ta!le 5*.T and disa!le the foreign key constraint in the ta!le *-.: alter ta!le 5*.T disa!le primary key cascade+ In order to ena!le an integrity constraint, the clause ena!le is used instead of disa!le. 0 constraint can only !e ena!led successfully if no tuple in the ta!le violates the constraint. $therwise an error message is displayed. /ote that for ena!lingIdisa!ling an integrity constraint it is important that you have named the constraints. In order to identify those tuples that violate an integrity constraint whose activation failed, one can use the clause e%ceptions into *JC*.TI$/S with the alter ta!le statement. *JC*.TI$/S is a ta!le that stores information a!out violating tuples.2 *ach tuple in this ta!le is identified

!y the attri!ute <$7I5. *very tuple in a data!ase has a pseudoBcolumn <$7I5 that is used to identify tuples. Gesides the rowid, the name of the ta!le, the ta!le owner as well as the name of the violated constraint are stored. *%ample: 0ssume we want to add an integrity constraint to our ta!le *-. which re uires that each manager must earn more than :,,,: alter ta!le *-. add constraint manager sal check"=$G D3 9-0/0F*<9 or S04 (3 :,,,# e%ceptions into *JC*.TI$/S+ If the ta!le *-. already contains tuples that violate the constraint, the constraint cannot !e activated and information a!out violating tuples is automatically inserted into the ta!le *JC*.TI$/S. 5etailed information a!out the violating tuples can !e o!tained !y 8oining the ta!les *-. and *JC*.TI$/S, !ased on the 8oin attri!ute <$7I5: select *-.., C$/ST<0I/T from *-., *JC*.TI$/S where *-..<$7I5 3 *JC*.TI$/S.<$7 I5+
2Gefore

this ta!le can !e used, it must !e created using the SK4 script utle%cept.s l which can !e found in the directory L$<0C4* C$-*Ird!msIadmin.

:? Tuples contained in the uery result now can !e modified "e.g., !y increasing the salary of managers# such that adding the constraint can !e performed successfully. /ote that it is important to delete MoldN violations from the relation *JC*.TI$/S !efore it is used again. If a ta!le is used as a reference of a foreign key, this ta!le can only !e dropped using the command drop ta!le 'ta!le( cascade constraints+. 0ll other data!ase o!8ects that refer to this ta!le "e.g., triggers, see Section 5.1# remain in the data!ase system, !ut they are not valid. Information a!out integrity constraints, their status "ena!led, disa!led# etc. is stored in the data dictionary, more precisely, in the ta!les OS*< C$/ST<0I/TS and OS*< C$/S C$/ST<0I/TS.

5.1 Triggers

5.1.1 $verview The different types of integrity constraints discussed so far provide a declarative mechanism to associate MsimpleN conditions with a ta!le such as a primary key, foreign keys or domain constraints. Comple% integrity constraints that refer to several ta!les and attri!utes "as they

are known as assertions in the SK4 standard# cannot !e specified within ta!le definitions. Triggers, in contrast, provide a procedural techni ue to specify and maintain integrity constraints. Triggers even allow users to specify more comple% integrity constraints since a trigger essentially is a .4ISK4 procedure. Such a procedure is associated with a ta!le and is automatically called !y the data!ase system whenever a certain modification "event# occurs on that ta!le. -odifications on a ta!le may include insert, update, and delete operations "$racle >#. 5.1.1 Structure of Triggers 0 trigger definition consists of the following "optional# components: E trigger name create &or replace) trigger 'trigger name( E trigger time point !efore H after E triggering event"s# insert or update &of 'column"s#() or delete on 'ta!le( E trigger type "optional# for each row E trigger restriction "only for for each row triggers D# when "'condition(# E trigger !ody '.4ISK4 !lock( The clause replace reBcreates a previous trigger definition having the same 'trigger name(. The name of a trigger can !e chosen ar!itrarily, !ut it is a good programming style to use 5, a trigger name that reflects the ta!le and the event"s#, e.g., upd ins *-.. 0 trigger can !e invoked !efore or after the triggering event. The triggering event specifies !efore "after# which operations on the ta!le 'ta!le( the trigger is e%ecuted. 0 single event is an insert, an update, or a delete+ events can !e com!ined using the logical connective or. If for an update trigger no columns are specified, the trigger is e%ecuted after "!efore# 'ta!le( is updated. If the trigger should only !e e%ecuted when certain columns are updated, these columns must !e specified after the event update. If a trigger is used to maintain an integrity constraint, the triggering events typically correspond to the operations that can violate the integrity constraint. In order to program triggers efficiently "and correctly# it is essential to understand the difference

!etween a row level trigger and a statement level trigger. 0 row level trigger is defined using the clause for each row. If this clause is not given, the trigger is assumed to !e a statement trigger. 0 row trigger e%ecutes once for each row after "!efore# the event. In contrast, a statement trigger is e%ecuted once after "!efore# the event, independent of how many rows are affected !y the event. 6or e%ample, a row trigger with the event specification after update is e%ecuted once for each row affected !y the update. Thus, if the update affects 1, tuples, the trigger is e%ecuted 1, times, for each row at a time. In contrast, a statement trigger is only e%ecuted once. 7hen com!ining the different types of triggers, there are twelve possi!le trigger configurations that can !e defined for a ta!le: trigger time point trigger type event !efore after statement row insert J J J J update J J J J delete J J J J 6igure 2: Trigger Types <ow triggers have some special features that are not provided !y statement triggers: $nly with a row trigger it is possi!le to access the attri!ute values of a tuple !efore and after the modification "!ecause the trigger is e%ecuted once for each tuple#. 6or an update trigger, the old attri!ute value can !e accessed using :old.'column( and the new attri!ute value can !e accessed using :new.'column(. 6or an insert trigger, only :new.'column( can !e used, and for a delete trigger only :old.'column( can !e used "!ecause there e%ists no old, respectively, new value of the tuple#. In these cases, :new.'column( refers to the attri!ute value of 'column( of the inserted tuple, and :old.'column( refers to the attri!ute value of 'column( of the deleted tuple. In a row trigger thus it is possi!le to specify comparisons !etween old and new attri!ute values in the .4ISK4 !lock, e.g., Mif :old.S04 ' :new.S04 then . . . N. If for a row trigger the trigger time point !efore is specified, it is even possi!le to modify the new values of the row, e.g., :new.S04 :3 :new.S04 1.,5 or :new.S04 :3 :old.S04.

Such modifications are not possi!le with after row triggers. In general, it is advisa!le to use a after row trigger if the new row is not modified in the .4ISK4 !lock. $racle then can process 51 these triggers more efficiently. Statement level triggers are in general only used in com!ination with the trigger time point after. In a trigger definition the when clause can only !e used in com!ination with a for each row trigger. The clause is used to further restrict when the trigger is e%ecuted. 6or the specification of the condition in the when clause, the same restrictions as for the check clause hold. The only e%ceptions are that the functions sysdate and user can !e used, and that it is possi!le to refer to the oldInew attri!ute values of the actual row. In the latter case, the colon M:N must not !e used, i.e., only old.'attri!ute( and new.'attri!ute(. The trigger !ody consists of a .4ISK4 !lock. 0ll SK4 and .4ISK4 commands e%cept the two statements commit and roll!ack can !e used in a trigger9s .4ISK4 !lock. 6urthermore, additional if constructs allow to e%ecute certain parts of the .4ISK4 !lock depending on the triggering event. 6or this, the three constructs if inserting, if updating&"9'column(9#), and if deleting e%ist. They can !e used as shown in the following e%ample: create or replace trigger emp check after insert or delete or update on *-. for each row !egin if inserting then '.4ISK4 !lock( end if + if updating then '.4ISK4 !lock( end if + if deleting then '.4ISK4 !lock( end if + end+ It is important to understand that the e%ecution of a trigger9s .4ISK4 !lock !uilds a part of the transaction that contains the triggering event. Thus, for e%ample, an insert statement in a .4ISK4 !lock can cause another trigger to !e e%ecuted. -ultiple triggers and modifications thus can lead to a cascading e%ecution of triggers. Such a se uence of

triggers terminates successfully if "1# no e%ception is raised within a .4ISK4 !lock, and "1# no declaratively specified integrity constraint is violated. If a trigger raises an e%ception in a .4ISK4 !lock, all modifications up to the !eginning of the transaction are rolled !ack. In the .4ISK4 !lock of a trigger, an e%ception can !e raised using the statement raise application error "see Section :.1.5#. This statement causes an implicit roll!ack. In com!ination with a row trigger, raise application error can refer to oldInew values of modified rows: raise application error"B1,,1,, 9Salary increase from 9 HH to char":old.S04# HH 9 to 9 to char":new.S04# HH 9 is too high9#+ or raise application error"B1,,2,, 9*mployee Id 9 HH to char":new .*-./$# HH 9 does not e%ist.9#+ 51 5.1.2 *%ample Triggers Suppose we have to maintain the following integrity constraint: MThe salary of an employee different from the president cannot !e decreased and must also not !e increased more than 1,P. 6urthermore, depending on the 8o! title, each salary must lie within a certain salary range. 7e assume a ta!le S04F<05* that stores the minimum "-I/S04# and ma%imum "-0JS04# salary for each 8o! title "=$G#. Since the a!ove condition can !e checked for each employee individually, we define the following row trigger: trig1.s l create or replace trigger check salary *-. after insert or update of S04, =$G on *-. for each row when "new.=$G D3 9.<*SI5*/T9# Q Q trigger restriction declare minsal, ma%sal S04F<05*.-0JS04PTR.*+ !egin Q Q retrieve minimum and ma%imum salary for =$G select -I/S04, -0JS04 into minsal, ma%sal from S04F<05* where =$G 3 :new.=$G+ Q Q If the new salary has !een decreased or does not lie within the salary range, Q Q raise an e%ception if ":new.S04 ' minsal or :new.S04 ( ma%sal# then raise application error"B1,115, 9Salary range e%ceeded9#+ elsif ":new.S04 ' :old.S04# then raise application error"B1,12,, 9Salary has !een decreased9#+

elsif ":new.S04 ( 1.1 :old.S04# then raise application error"B1,125, 9-ore than 1,P salary increase9#+ end if + end+ 7e use an after trigger !ecause the inserted or updated row is not changed within the .4ISK4 !lock "e.g., in case of a constraint violation, it would !e possi!le to restore the old attri!ute values#. /ote that also modifications on the ta!le S04F<05* can cause a constraint violation. In order to maintain the complete condition we define the following trigger on the ta!le S04F<05*. In case of a violation !y an update modification, however, we do not raise an e%ception, !ut restore the old attri!ute values. 52 trig1.s l create or replace trigger check salary S04F<05* !efore update or delete on S04F<05* for each row when "new.-I/S04 ( old.-I/S04 or new.-0JS04 ' old.-0JS04# Q Q only restricting a salary range can cause a constraint violation declare 8o! emps num!er"2# :3 ,+ !egin if deleting then Q Q 5oes there still e%ist an employee having the deleted 8o! S select count"# into 8o! emps from *-. where =$G 3 :old.=$G+ if 8o! emps D3 , then raise application error"B1,1:,, 9 There still e%ist employees with the 8o! 9 HH :old.=$G#+ end if + end if + if updating then Q Q 0re there employees whose salary does not lie within the modified salary range S select count"# into 8o! emps from *-. where =$G 3 :new.=$G and S04 not !etween :new.-I/S04 and :new.-0JS04+ if 8o! emps D3 , then Q Q restore old salary ranges :new.-I/S04 :3 :old.-I/S04+ :new.-0JS04 :3 :old.-0JS04+ end if + end if + end+ In this case a !efore trigger must !e used to restore the old attri!ute

values of an updated row. Suppose we furthermore have a column GO5F*T in our ta!le 5*.T that is used to store the !udget availa!le for each department. 0ssume the integrity constraint re uires that the total of all salaries in a department must not e%ceed the department9s !udget. Critical operations on the relation *-. are insertions into *-. and updates on the attri!utes S04 or 5*.T/$. 5: trig2.s l create or replace trigger check !udget *-. after insert or update of S04, 5*.T/$ on *-. declare cursor 5*.T CO< is select 5*.T/$, GO5F*T from 5*.T+ 5/$ 5*.T.5*.T/$PTR.*+ 044S04 5*.T.GO5F*TPTR.*+ 5*.T S04 num!er+ !egin open 5*.T CO<+ loop fetch 5*.T CO< into 5/$, 044S04+ e%it when 5*.T CO<P/$T6$O/5+ select sum"S04# into 5*.T S04 from *-. where 5*.T/$ 3 5/$+ if 5*.T S04 ( 044S04 then raise application error"B1,215, 9Total of salaries in the department 9 HH to char"5/$# HH 9 e%ceeds !udget9#+ end if + end loop+ close 5*.T CO<+ end+ In this case we use a statement trigger on the relation *-. !ecause we have to apply an aggregate function on the salary of all employees that work in a particular department. 6or the relation 5*.T, we also have to define a trigger which, however, can !e formulated as a row trigger. 5.1.: .rogramming Triggers 6or programmers, row triggers are the most critical type of triggers !ecause they include several restrictions. In order to ensure read consistency, $racle performs an e%clusive lock on the ta!le at the !eginning of an insert, update, or delete statement. That is, other users cannot access this ta!le until modifications have !een successfully completed. In this case, the ta!le

currently modified is said to !e a mutating ta!le. The only way to access a mutating ta!le in a trigger is to use :old.'column( and :new.'column( in connection with a row trigger. *%ample of an erroneous row trigger: create trigger check sal *-. after update of S04 on *-. for each row 55 declare sal sum num!er+ !egin select sum"S04# into sal sum from *-.+ ...+ end+ 6or e%ample, if an update statement of the form update *-. set S04 3 S04 1.1 is e%ecuted on the ta!le *-., the a!ove trigger is e%ecuted once for each modified row. 7hile the ta!le is !eing modified !y the update command, it is not possi!le to access all tuples of the ta!le using the select command, !ecause it is locked. In this case we get the error message $<0B,:,?1: ta!le *-. is mutating, trigger may not read or modify it $<0B,;511: at line : $<0B,:,AA: error during e%ecution of trigger 9CC*C@TS04T*-.9 The only way to access the ta!le, or more precisely, to access the modified tuple, is to use :old.'column( and :new.'column(. It is recommended to follow the rules !elow for the definition of integrity maintaining triggers: identify operations and ta!les that are critical for the integrity constraint for each such ta!le check if constraint can !e checked at row level then if checked rows are modified in trigger then use !efore row trigger else use after row trigger else use after statement trigger Triggers are not e%clusively used for integrity maintenance. They can also !e used for E -onitoring purposes, such as the monitoring of user accesses and modifications on certain sensitive ta!les. E 4ogging actions, e.g., on ta!les: create trigger 4$F *-. after insert or update or delete on *-. !egin if inserting then

insert into *-. 4$F values"user, 9I/S*<T9, sysdate#+ 5; end if + if updating then insert into *-. 4$F values"user, 9O.50T*9, sysdate#+ end if + if deleting then insert into *-. 4$F values"user, 95*4*T*9, sysdate#+ end if + end+ Gy using a row trigger, even the attri!ute values of the modified tuples can !e stored in the ta!le *-. 4$F. E automatic propagation of modifications. 6or e%ample, if a manager is transfered to another department, a trigger can !e defined that automatically transfers the manager9s employees to the new department. 5.1.5 -ore a!out Triggers If a trigger is specified within the SK4U.lus shell, the definition must end with a point M.N in the last line. Issuing the command run causes SK4U.lus to compile this trigger definition. 0 trigger definition can !e loaded from a file using the command V. /ote that the last line in the file must consist of a slash MIN. 0 trigger definition cannot !e changed, it can only !e reBcreated using the or replace clause. The command drop 'trigger name( deletes a trigger. 0fter a trigger definition has !een successfully compiled, the trigger automatically is ena!led. The command alter trigger 'trigger name( disa!le is used to deactivate a trigger. 0ll triggers defined on a ta!le can !e "de#activated using the command alter ta!le 'Ta!elle( ena!le H disa!le all trigger+ The data dictionary stores information a!out triggers in the ta!le OS*< T<IFF*<S. The information includes the trigger name, type, ta!le, and the code for the .4ISK4 !lock. 5>

Вам также может понравиться