1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Teach Yourself PL/SQL in 21 Days- P7 ppt

50 369 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Analysis and Extension of Nested Tables in PL/SQL
Trường học Unknown University
Chuyên ngành Database Systems / PL/SQL Programming
Thể loại Lecture Notes
Năm xuất bản Unknown Year
Thành phố Unknown City
Định dạng
Số trang 50
Dung lượng 2,58 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

L ISTING 10.4 The extend Method, Adding Entries to a Nested Table 1: DECLARE 2: --Declare a cursor that returns all department records.. pack-Removing Entries from a Nested Table You can

Trang 1

Collections 277

10

The key here is that the arguments to the constructor are dept1anddept2 Both

of those are records of type department%ROWTYPE, and so match the element type

of the table Obviously it’s a bit cumbersome to set things up this way

To add more entries to a table than those you created with the constructor, you need toextend the table, as discussed in the following section

Extending a Nested Table

To extend a nested table so that you can add more entries to it, use the extendmethod

Theextendmethod allows you to add one entry, or several entries It also allows you toclone an existing entry one or more times The syntax for the extendmethod is as fol-lows

collection.extend[(entries_to_add[, entry_to_clone])];

In this syntax the parameters are as follows:

• collectionis the name of the nested table

• entries_to_addis a variable or constant indicating the number of new entries youwant to add

• entry_to_cloneis a variable or constant indicating which entry you want to clone

Listing 10.4 shows the extendmethod being used and illustrates how constructors work

L ISTING 10.4 The extend Method, Adding Entries to a Nested Table

1: DECLARE 2: Declare a cursor that returns all department records.

3: CURSOR all_depts IS 4: SELECT * 5: FROM department 6: ORDER BY dept_name;

7:

8: Define a nested table type.

9: TYPE dept_table IS TABLE OF department%ROWTYPE;

Trang 2

20: Initialize the table by creating one empty entry.

34: Display the results.

35: FOR inx1 IN 1 depts_max+5 LOOP 36: DBMS_OUTPUT.PUT_LINE ( 37: depts(inx1).dept_id ||

depart-TheFORloop in lines 23–29 reads the department records, and inserts them into thetable Before each record is inserted, a call to extendis made in order to add space forthe new entry After all the data has been read, another call to extendis made in line 32

L ISTING 10.4 continued

OUTPUT

A NALYSIS

Trang 3

Collections 279

10

to clone the first entry five times The last FORloop, in lines 35–39, dumps the contents

of the table to the screen (if you are using SQL*Plus) by using the DBMS_OUTPUTage Sure enough, you can see that the first entry has been replicated five more times atthe end of the table

pack-Removing Entries from a Nested Table

You can remove entries from a nested table by using the deletemethod, just as you dowith index-by tables The following example deletes entry 10 from the deptstable:

nested_table.trim[(entries_to_trim)];

In this syntax the parameters are as follows:

• nested_tableis the name of the nested table

• entries_to_trimis the number of entries to remove from the end The default

is1.The trim method applies only to nested tables and variable-sized arrays It cannot beapplied to index-by tables

Listing 10.5 is an extension of Listing 10.4 This time, after the new entries are added tothe table and displayed, the trimmethod is used to remove them

L ISTING 10.5 The trim Method

1: DECLARE 2: Declare a cursor that returns all department records.

3: CURSOR all_depts IS 4: SELECT * 5: FROM department 6: ORDER BY dept_name;

7:

8: Define a nested table type.

9: TYPE dept_table IS TABLE OF department%ROWTYPE;

Trang 4

12: hold the employee records that we read in.

13: depts dept_table;

14: depts_max PLS_INTEGER;

15: inx1 PLS_INTEGER;

16: BEGIN 17: Initialize the index into the table.

30:

31: Clone the first entry five times.

32: depts.extend(5,1);

33:

34: Display the results.

35: FOR inx1 IN 1 depts_max+5 LOOP 36: DBMS_OUTPUT.PUT_LINE ( 37: depts(inx1).dept_id ||

49: Display the results.

50: FOR inx1 IN 1 depts_max+5 LOOP 51: IF depts.exists(inx1) THEN 52: DBMS_OUTPUT.PUT_LINE ( 53: depts(inx1).dept_id ||

Trang 5

deletemethod is called in line 44 to delete the first entry as well Line 47 displays thenew count, telling how many entries are now in the table It also serves a more interest-ing purpose than that: PL/SQL doesn’t seem to recognize that you trimmed and deletedentries until after you reference the table’s count, so line 47 is really a bug workaround.

Finally, lines 50–56 display the table entries that remain after the deleting and trimming

OUTPUT

A NALYSIS

If you remove line 47 (which invokes the count method) from Listing 10.5, and run it again, the second list of departments will match the first In other words, the exists method won’t recognize that you deleted some entries.

This is true with Oracle release 8.1.5, and is almost certainly a bug The workaround is to invoke the count method at least once.

Note

Using Variable-Sized Arrays

Like nested tables, variable-sized arrays or varrays also came into existence with

the release of Oracle8 Varrays are similar to nested tables, but they have a fixed

maximum size They differ from nested tables in that when you store a varray into a base column, the order of elements is preserved

data-N EW T ERM

Trang 6

Declaring and Initializing a Varray

To create a varray, you use the VARRAYkeyword in a type declaration to create an arraytype Then you can use that type to declare one or more variables The syntax for declar-ing a varray type is as follows

TYPE type_name IS {VARRAY|VARYING ARRAY} (size) OF entry_type [NOT NULL];

In this syntax the parameters are as follows:

• type_nameis the name of the array type

• sizeis the number of elements you want the array to hold

• entry_typeis the data type for elements of the array

• NOT NULLprohibits array entries from being null

Varrays need to be initialized just as nested tables do Before you can use a varray, youneed to call its constructor You can pass values to the constructor, and those values areused to create array elements, or you can invoke the constructor with no parameters inorder to create an empty array

The code in Listing 10.6 shows a varray being declared, and the constructor being called

to create the array with some initial data

L ISTING 10.6 Declaring and Creating a Varray

1: DECLARE 2: Define an array type 3: TYPE dept_array IS VARRAY(100) OF VARCHAR2(30);

12: depts := dept_array (‘Dept One’,’Dept Two’);

13:

14: Display the contents of the two entries.

15: FOR inx1 IN 1 2 LOOP 16: DBMS_OUTPUT.PUT_LINE(depts(inx1));

Trang 7

Collections 283

10

Dept One Dept Two

Line 3 declares a type that results in a 100-element array of VARCHAR2(30)ues The deptsvariable is declared in line 6 to be of this type In line 12 thearray is initialized by calling the constructor In this example, two values are supplied tothe constructor, so the array is created with those two elements The size of the array isstill 100 because that’s what is specified in the type declaration The elements created bythe constructor are numbers 1 and 2, and elements 3 through 100 are empty

val-Adding and Removing Data from a Varray

After you’ve initialized a varray, you can add data to and remove it from the varray just

as you do with a nested table If you want to add more elements to the array than youcreated when you initialized it, you can call the extendmethod However, you can onlyextend an array up to the maximum size specified in the array type definition

Listing 10.7 shows the contents of the departmenttable being read into a varray

L ISTING 10.7 Reading Data into a Varray

1: DECLARE 2: Declare a cursor that returns all department records.

3: CURSOR all_depts IS 4: SELECT * 5: FROM department 6: ORDER BY dept_name;

7:

8: Define a varray type.

9: TYPE dept_array IS VARRAY(100) OF department%ROWTYPE;

Trang 8

31: Display the results.

32: FOR inx2 IN 1 depts.count LOOP 33: DBMS_OUTPUT.PUT_LINE ( 34: depts(inx2).dept_id ||

Taking Advantage of Bulk Binding

PL/SQL bulk binding is a new feature with Oracle8i Bulk binding lets you code

SQL statements that operate on all entries in a collection, without having to loopthrough that collection by using PL/SQL code Several of the examples so far in this les-son have used a cursor FORloop to load data from a database table into a PL/SQL table

or array The switch from SQL (for the fetch) to PL/SQL (to add the data to the array) is

called a context switch, and consumes quite a bit of overhead You can use the bulk

bind-ing feature to avoid much of that overhead

Trang 9

Collections 285

10

You can use the BULK COLLECTkeywords to have the results of a SELECTstatementplaced directly into a collection You can use BULK COLLECTwithSELECT INTOstate-ments, and also with FETCHstatements For example, if dept_idsanddept_nameswereboth nested tables, you could issue the following SELECTstatement:

SELECT dept_id, dept_name BULK COLLECT INTO dept_ids, dept_names FROM department;

If you had a cursor named all_deptsthat returned the same data, you could write BULK COLLECTinto the FETCHstatement, like this:

Listing 10.8 shows an example of BULK COLLECTbeing used to load all departmentnames and IDs into a nested table

L ISTING 10.8 An Example Showing the Use of BULK COLLECT

1: DECLARE 2: Declare a cursor that returns all department records.

3: CURSOR all_depts IS 4: SELECT dept_id, dept_name 5: FROM department

6: ORDER BY dept_name;

7:

8: Define a nested table type for each column.

9: TYPE dept_id IS TABLE OF department.dept_id%TYPE;

10: TYPE dept_name IS TABLE OF department.dept_name%TYPE;

18: FETCH all_depts BULK COLLECT INTO dept_ids, dept_names;

19: CLOSE all_depts;

20:

21: Display the results.

22: FOR inx1 IN 1 dept_ids.count LOOP

INPUT

continues

Trang 10

23: DBMS_OUTPUT.PUT_LINE ( 24: dept_ids(inx1) ||

Theall_deptscursor declared in lines 3–6 returns two values: the department

ID and name Lines 9 and 10 declare nested table types for each of thesecolumns Corresponding nested table variables are declared in lines 13–14 The FETCH

statement in line 18 then uses the BULK COLLECTkeyword to read all the data selecteddirectly into the arrays This is much faster than fetching one row at a time using aPL/SQL loop

Note that Listing 10.8 contain no call to the nested tables’ constructor methods The

FETCHstatement takes care of that for you

The ability to do bulk binds is a great feature The single annoying thing about it is thatyou cannot declare a nested table of department%rowtype, and use that as the target

BULK COLLECTwon’t handle tables of records

con-L ISTING 10.8 continued

Trang 11

Collections 287

10

Looking back at Listing 10.8, let’s say you wanted to set the employee count to null foreach department You could do that, after selecting the department information into thenested tables, by writing the following FORALLstatement:

FORALL x IN dept_ids.first dept_id.last UPDATE department

SET no_of_emps := NULL WHERE dept_id = dept_ids(x);

In this case, index xranges from the first entry in the dept_idtable to the last If youdon’t want the statement to apply to all entries in the table, you can specify a differentrange The use of dept_ids(x)indicates that this is where you want nested table valuessubstituted into the SQL statement when it executes

Listing 10.9 shows a similar FORALLstatement being used to change all the departmentnames to uppercase

L ISTING 10.9 An Example Showing the Use of FORALL

1: DECLARE 2: Declare a cursor that returns all department records.

3: CURSOR all_depts IS 4: SELECT dept_id, dept_name 5: FROM department

6: ORDER BY dept_name;

7:

8: Define a nested table type for each column.

9: TYPE dept_id IS TABLE OF department.dept_id%TYPE;

10: TYPE dept_name IS TABLE OF department.dept_name%TYPE;

18: FETCH all_depts BULK COLLECT INTO dept_ids, dept_names;

19: CLOSE all_depts;

20:

21: Uppercase the names and Display the results.

22: FOR inx1 IN 1 dept_ids.count LOOP 23: dept_names(inx1) := UPPER(dept_names(inx1));

24:

25: DBMS_OUTPUT.PUT_LINE ( 26: dept_ids(inx1) ||

27: ‘ ‘ || dept_names(inx1));

28: END LOOP;

INPUT

continues

Trang 12

30: FORALL x IN dept_ids.first dept_ids.last 31: UPDATE department

32: SET dept_name = dept_names(x) 33: WHERE dept_id = dept_ids(x);

34: END;

35: /

Aside from lines 30–33, this listing is almost exactly like Listing 10.8 One line(line 23) has been added to the FORloop to make each department name upper-case The FORALLstatement writes the new names back to the database by using an

UPDATEstatement.FORALLcauses a bulk bind to be used, which is much more efficientthan if you had updated each row individually inside of a PL/SQL loop

state-Exception Handling for Collections

Some PL/SQL exceptions are directly related to collections These are listed in Table 10.1

T ABLE 10.1 Collection-Related Exceptions

Trang 13

Collections 289

10

SUBSCRIPT_OUTSIDE_LIMIT You used a subscript with a varray that was larger than the maximum

supported by the varray’s type declaration.

VALUE_ERROR You used a subscript that couldn’t be converted to an integer.

When writing code that deals with collections, you can either trap these exceptions orwrite code that avoids them You can avoid NO_DATA_FOUND, for example, by testing thevalidity of each entry with the existsmethod before you attempt to access the value theentry The following snippet of code shows how this is done:

IF dept_names.EXISTS(10) THEN ELSE

/* Element 10 does not exist */

END IF;

You can avoid subscript errors by careful coding If you’re working with varray, youshould know how many elements you declared that varray to hold in the first place Ifyou’re working with a nested table, and you aren’t sure of the size anymore, you can usethe count method to check and see how large the table is

Summary

Today you’ve learned how to declare and use records You have also had an opportunity

to learn about all of PL/SQL’s collection types, including index-by tables, nested tables,and variable-sized arrays PL/SQL’s bulk bind feature delivers some significant perfor-mance improvements To use bulk binds, you need to be working with data stored in col-lections You can then execute SQL statements that are automatically applied to eachentry in a collection

Q&A

Q How do I choose whether to use a variable-sized array in my code, a nested table, or an index-by table?

A If you’re dealing with database columns, then you should first base your decision

on the column type For example, if you’re reading a VARRAYcolumn from a base table, don’t read it into a PL/SQL nested table Read it into a PL/SQL varray

data-If this issue doesn’t apply to your situation, then base your decision on whetheryou will be working with a fixed number of elements Varrays can only grow to thelimit specified in their type declaration Tables can grow to any size If you can’teasily conceive of a maximum size, then use a table

Trang 14

Q Are nested tables the preferred choice for tables? Why would I ever want to use an index-by table?

A Had nested tables been created first, Oracle might never have developed the

index-by type However, both are available, and you must choose between them If youneed an array of a PL/SQL-specific datatype, such as a BOOLEAN,NATURAL, or

INTEGER, then an index-by table is your only choice The other thing to look at isthe indexes you use Nested tables require that your indexes are consecutive, such

as 1, 2, 3, and so on Index-by tables allow you to use any arbitrary index value for

an entry, such as 1, 987234, 345, and so on

Q Why are bulk binds so great?

A Bulk binds reduce the number of PL/SQL to SQL context switches Each time your

PL/SQL program executes an SQL statement, control switches to the SQL world,and a context switch occurs Bulk binds allow you to operate on a large collection

of records with only one context switch occurring The result is less overhead andfaster execution

Q What is a PL/SQL record?

A A PL/SQL record is a variable that contains several related elements The elements

are not treated as an array, and they do not all have to have the same datatype.Records are commonly declared to match table definitions, or to match thecolumns returned by a cursor They simplify code by allowing you to packagerelated values, such as the columns in a row, into one unit

1 Name the three collection types PL/SQL supports

2 What declaration would you use to declare a variable named emp_namewith adatatype and size that exactly match the definition of the employee.emp_namecol-umn in the database?

3 What declaration would you use to declare a record named empthat matches thedefinition of a row in the employeetable?

Trang 15

Collections 291

10

4 What method can you call on to be sure that a collection element really exists?

5 What must you be sure to do before you can add data to a nested table or to a varray?

Trang 17

D AY 11

Writing Database Triggers

by Jonathan Gennick

Today’s lesson discusses database triggers A trigger is used to write procedural

logic that is invoked in response to a specific event Creative application ofdatabase triggers will enable you to accomplish many useful things that other-wise would be impossible Examples of what you can do with triggers includereplicating data, storing data redundantly to avoid frequent table joins, andenforcing complex business rules

Today, you will learn how to:

• Differentiate among the several types of triggers

• Create triggers that fire in response to specific DML statements that areissued against a table

• Use triggers to modify data being inserted into a table

• Use triggers to maintain a history of changes to a record

• Use the new database and schema event triggers that were introducedwith Oracle8i

Trang 18

• Data definition language (DDL) triggers

• Database event triggersDML triggers are the traditional INSERT,UPDATE, and DELETEtriggers that Oracle hassupported for years Instead-of triggers were introduced with Oracle8 as a way to make itpossible to update certain types of views DDL triggers and Database event triggers arenew with Oracle8i

DML Triggers

DML triggers are the traditional triggers that can be defined on a table, and are executed,

or fired, in response to the following events:

• A row is inserted into a table

• A row in a table is updated

• A row in a table is deleted

It is not possible to define a trigger to fire when a row is selected

A DML trigger definition consists of these basic parts:

• The event that fires the trigger

• The database table on which the event must occur

• An optional condition controlling when the trigger is executed

• A PL/SQL block containing the code to be executed when the trigger is fired, or a

CALLstatement to a stored procedure

A trigger is a database object, like a table or an index When you define a trigger, itbecomes part of the database and is always executed when the event for which it isdefined occurs It doesn’t matter if the event is triggered by someone typing in an SQLstatement using SQL*Plus, running a client-server program that updates the database, orrunning a utility like Oracle’s SQL*Loader in order to bulk-load data Because of this, atrigger serves as a choke point, allowing you to perform critical validation or computa-tions in response to database changes, no matter what the source

Trang 19

Writing Database Triggers 295

11

An Example of a DML Trigger

Suppose for a moment that you wanted to be sure that all department names were storedusing uppercase letters Perhaps you are doing this to facilitate searching on that field

Listing 11.1 shows one way to do this with a trigger

L ISTING 11.1 Example of a Trigger

1: CREATE OR REPLACE TRIGGER department_insert_update 2: BEFORE INSERT OR UPDATE ON department

3: FOR EACH ROW 4: DECLARE 5: dup_flag INTEGER;

6: BEGIN 7: Force all department names to uppercase.

8: :NEW.dept_name := UPPER(:NEW.dept_name);

9: END;

10: /

Line 1 tells Oracle to create this trigger with the name

department_insert_updateand to replace any existing trigger of the samename if necessary Line 2 says that it will be fired whenever a new row is inserted intothe department table or whenever a department record is changed In line 8 there is oneline of code that uses the built-in UPPERfunction to force the department name to upper-case Notice the reference to :NEW This is the default alias for the new value of therecord The alias :OLDcan be used to refer to the old value of a field before an updatetakes effect Line 3 tells Oracle to fire this trigger once for each row modified If youwere to issue an UPDATEstatement to change the names of all departments in the table,this trigger would be fired for each one of those records

To demonstrate the effect of this trigger, try issuing the statements shown in Listing 11.2

L ISTING 11.2 Testing the department_insert_update Trigger

1: INSERT INTO department (dept_id, dept_name) VALUES (10,’payroll’);

Trang 20

Note that the trigger has forced all department names to uppercase regardless ofwhether the name was the result of a new record inserted or an existing recordthat was updated

Types of DML Triggers

DML triggers can be classified in two different ways: by when they fire in relation to thetriggering SQL statement, or by whether or not they fire for each row affected by thetriggering SQL statement This results in four basic trigger types

There are two choices when a trigger fires in relation to an SQL statement: either

before or after Before triggers are executed before the triggering SQL statement After triggers are executed following the triggering SQL statement.

A DML trigger is either a level trigger or a statement-level trigger A

row-level trigger executes once for each row affected by the triggering SQL ment, whereas a statement-level trigger is executed only once Only row-level triggershave access to the data values in the affected records Statement-level triggers do not.This is because SQL is a set-oriented language SQL statements can affect many or evenall rows in a table Statement-level triggers are only fired once, so it would not be possi-ble to resolve a column reference in such a trigger

state-The possible combinations of the choices result in the four DML trigger types listed inTable 11.1

T ABLE 11.1 The Four Basic Trigger Types

Before Statement Executed once for the triggering SQL statement

before that statement is executed.

Before Row Executed once for each record affected by the

trigger-ing SQL statement before the record in question is changed, deleted, or inserted

After Row Executed once for each record affected by the

trigger-ing SQL statement after the record in question has been changed, deleted, or inserted.

After Statement Executed once for the triggering SQL statement after

that statement has been executed.

Triggers execute in response to an SQL statement and can be defined for the INSERT,

UPDATE, and DELETEstatements These are often referred to as insert triggers, update gers, and delete triggers, respectively Together with the four types from Table 11.1, this

trig-gives a total of 12 possible triggers that you can define on a table In addition, any one

N EW T ERM

N EW T ERM

A NALYSIS

Trang 21

Writing Database Triggers 297

11

Because there are four possible triggers that can be created for a specific SQL statement,

it makes sense to ask about the execution order Which trigger gets executed first? Whichlast? What if multiple triggers are defined identically? Figure 11.1 shows the order ofexecution of the various trigger types in relation to each other and in relation to the trig-gering SQL statement

The SELECT statement is the only data manipulation statement for which no triggers can be defined.

Note

F IGURE 11.1

Trigger execution order.

After Statement Trigger

Before Statement Trigger

Before Row Trigger

One row is inserted, updated, or deleted.

After Row Trigger

This sequence occurs for each row affected by the SQL statement

Triggers defined identically are executed in no particular order If you write several thatfire before a row is updated, you must ensure that the integrity of the database does notdepend on the order of execution

Trang 22

The Syntax for Defining a Database Trigger

This section shows the syntax used to define a traditional DML trigger on a databasetable Parts of the syntax get somewhat complex, but don’t be intimidated by that Thereare plenty of examples in this chapter to give you a good feel for how triggers are used

CREATE [OR REPLACE] TRIGGER [schema.]trigger_name {BEFORE|AFTER} verb_list ON [schema.]table_name [[REFERENCING correlation_names] FOR EACH ROW [WHEN (condition)]]

DECLARE declarations BEGIN

pl/sql_code END;

/

In this syntax, the parameters are as follows:

• schemarefers to the owner of an object When used before a trigger name, it refers

to the owner of the trigger When used before a table name, it refers to the owner

of the table

• trigger_nameis the name you want to give the trigger

• verb_listidentifies the SQL verbs that fire the trigger The syntax of the

verb_listis as follows:

{INSERT|DELETE|UPDATE [OF column_list]} [OR verb_list]

Do use before-update row-level triggers

for complex business rule enforcement, security checking, and performing com- plex calculations You want to do all these things before the row is inserted.

Do use after-update row-level triggers

for data replication and logging of changes.

Do use statement-level before triggers to

enforce security rules where the rule is not dependent on any values in the records being affected.

Don’t use before triggers for data

repli-cation and change logging because an integrity constraint or another trigger could prevent the SQL statement from completing.

Don’t use triggers to enforce referential

integrity in cases where you can use a declarative constraint instead.

Trang 23

Writing Database Triggers 299

11

The parameters in the verb list are

column_list Causes an update trigger to fire only when one of the

columns listed is changed Otherwise, the trigger fireswhenever any column in the table is changed

verb_list This is another iteration of the verb list You can create

a trigger that is fired by more than one SQL verb

• table_nameis the table on which the trigger is defined

• correlation_namesallows you to specify correlation names other than the default

ofOLDandNEW This is useful if the table on which the trigger is defined happens

to be named OLDorNEW, and can also be helpful in making the trigger code documenting The referencing clause looks like this:

self-{OLD AS old_alias|NEW AS new_alias [correlation_names]}

In the preceding syntax, the parameters are

old_alias This is a name you want to use when

refer-ring to the value of a field before the SQLverb executes

new_alias This is a name you want to use when

refer-ring to the value of a field after the SQL verbexecutes

correlation_names This is another iteration of the alias list You

can specify an alias for both old and new values

• conditionis an optional condition placed on the execution of the trigger This canonly be used on row-level triggers If conditionis present, the trigger will only befired when the condition is true The condition can be any Boolean expression,cannot contain any queries, and must use correlation names, in other words NEW

andOLD, to refer to column values in the row being changed

• declarationsconsists of any variable, record, or cursor declarations needed bythis PL/SQL block

• pl/sql_codeis the PL/SQL code that gets executed when the trigger fires

• DECLARE END;You can optionally replace the entire PL/SQL block with a CALL

statement that looks like this:

Trang 24

The correlation names: OLDand:NEWdeserve some extra explanation It iscommon when writing a trigger to need to reference the values in the recordbeing inserted, updated, or deleted Further, in the case of an update, it is often necessary

to access both the before and after values of a given field The correlation names :OLD

and:NEWare provided for this purpose These function much like a PL/SQL record :OLD

contains the field values before they are updated, and :NEWcontains the field values afterthe update takes place Use the standard dot notation, in other words :OLD.field_name,

to refer to the value of a particular field You will see examples of this in several of thelistings in this chapter

N EW T ERM

Accessing both before and after versions of a record usually only makes sense in an update trigger However, Oracle does allow you to reference both :OLD and :NEW in delete and insert triggers In an insert trigger, the field values in :OLD will be null and :NEW will contain the data to be insert-

ed In a delete trigger, the situation is reversed The field values in :OLD tain the data about to be deleted and the :NEW values will be null

con-Note

Uses for Triggers

The possible uses for database triggers are varied and are limited only by your tion Some common uses are

imagina-• Enforcing business rules

• Maintaining referential integrity

• Enforcing security

• Maintaining a historical log of changes

• Generating column values, including primary key values

• Replication of dataThe next few sections show some examples of these uses

Maintaining Data Integrity

A common use for triggers is to assist in maintaining the integrity of the data stored inthe database Suppose that you wanted to store a count of the number of employees ineach department and that you wanted to store this count in the department table Youwould first add an employee count field to the department table using a statement likethis:

ALTER TABLE department ADD (no_of_emps NUMBER(38));

Trang 25

Writing Database Triggers 301

11

Theno_of_empsfield is used to keep track of the number of employees in any givendepartment Think of how this employee count could be maintained One possible solu-tion would be to have any program that adds an employee, deletes an employee, orchanges an employee’s department assignment to update this value appropriately Thiswould work as long as the programs always worked correctly, and as long you never for-got that the value needed to be maintained Unfortunately, as you add programmers to aproject and as the number of programs that need to maintain this value increases, thelikelihood of a mistake also increases Triggers provide you with a mechanism to central-ize the code to maintain a counter like this

Because you have to deal with inserts, updates, and deletes, three triggers are needed tomaintain the departmental employee count These are listed in Table 11.2

T ABLE 11.2 Triggers Needed to Maintain Department Employee Counts

Trigger Type What the Trigger Should Accomplish

Insert When an employee is added, this trigger needs to increment the count for

the appropriate department

Update When an employee’s department is changed, this trigger needs to

decre-ment the count for the previous departdecre-ment and incredecre-ment the count for the new department

Delete When an employee is deleted, this trigger needs to decrement the count

for the appropriate department.

These triggers will all be implemented as after triggers because you are only interested in adjusting the counts after a successful change You could implement them as before triggers, but if subsequent validation caused a transaction to be rolled back, the work the triggers had done would also need to be rolled back, resulting in extra work for the database engine.

Note

Listing 11.3 shows the code to create the three triggers needed to maintain employeecounts for each department

L ISTING 11.3 Triggers to Maintain Departmental Employee Counts

1: CREATE OR REPLACE TRIGGER emp_dept_ins 2: AFTER INSERT ON emp_dept

3: FOR EACH ROW

continues

INPUT

Ngày đăng: 15/12/2013, 05:15

TỪ KHÓA LIÊN QUAN