45
Triggers How triggers work Creating triggers • Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated with triggers Disabling triggers Dropping triggers Getting information about triggers

Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Embed Size (px)

Citation preview

Page 1: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Triggers• How triggers work• Creating triggers• Using triggers to maintain referential integrity• Multirow considerations• Nesting triggers• Rules associated with triggers• Disabling triggers• Dropping triggers• Getting information about triggers

Page 2: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

How Triggers Work• A trigger is a stored procedure that goes into effect

when you insert, delete, or update data in a table.• You can use triggers to perform a number of

automatic actions, such as• cascading changes• enforcing column restrictions• comparing the results of data modifications• maintaining the referential integrity of data across a

database.

Page 3: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

How Triggers Work

• A trigger is specific to one or more of the data modification operations, update, insert, and delete and is executed once for each SQL statement.

Page 4: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

How Triggers Work• For example, to prevent users from removing any publishing

companies from the publishers table, you could use this trigger:

create trigger del_pub on publishersfor deleteasbegin

rollback transactionprint ‘You cannot delete any publishers!’

end

Page 5: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

How Triggers Work• A trigger fires only after the data modification

statement has completed and Server has checked for any data type, rule, or integrity constraint violation.

• The trigger and the statement that fires it are treated as a single transaction that can be rolled back from within the trigger.

• If Server detects a severe error, the entire transaction is rolled back.

Page 6: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

How Triggers WorkTriggers are most useful in these situations:• Triggers can cascade changes through related tables in

the database.• Triggers can disallow, or roll back, changes that would

violate referential integrity, canceling the attempted data modification transaction.

• Triggers can enforce restrictions that are much more complex than those that are defined with rules.

• Triggers can perform simple “what if” analyses. For example, a trigger can compare the state of a table before and after a data modification and take action based on that comparison.

Page 7: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Creating TriggersHere is the complete create trigger syntax:create trigger [owner.]trigger_name

on [owner.]table_name{for / instead of {insert , update , delete}as SQL_statements

Or, using the if update clause:create trigger [owner.]trigger_name

on [owner.]table_namefor {insert , update}as

[if update (column_name )[{and | or} update (column_name )]...]

SQL_statements[if update (column_name )[{and | or} update (column_name )]...SQL_statements ]...

Page 8: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Creating TriggersSQL statements that are not allowed in triggers:

Since triggers execute as part of a transaction, the following statements are notallowed in a trigger:• All create commands, including create database, create table, create index,create procedure, create default, create rule, create trigger, and create view• All drop commands• alter table and alter database• truncate table• grant and revoke• update statistics• reconfigure• load database and load transaction• disk init, disk mirror, disk refit, disk reinit, disk remirror, disk unmirror• select into

Page 9: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Trigger Test Tables• Referential integrity triggers keep the values

of foreign keys in line with those in primary keys.

• When a data modification affects a key column, triggers compare the new column values to related keys by using temporary work tables called trigger test tables.

• When you write your triggers, you base your comparisons on the data that is temporarily stored in the trigger test tables.

Page 10: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Trigger Test TablesServer uses two special tables in trigger statements: the deleted table and the inserted table. These are temporary tables used in trigger tests.• The deleted table stores copies of the affected

rows during delete and update statements. During the execution of a delete or update statement, rows are removed from the trigger table and transferred to the deleted table. The deleted and trigger tables ordinarily have no rows in common.

Page 11: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Trigger Test Tables• The inserted table stores copies of the affected

rows during insert and update statements. During an insert or an update, new rows are added to the inserted and trigger tables at the same time. The rows in inserted are copies of the new rows in the trigger table.

• An update is a delete followed by an insert; the old rows are copied to the deleted table first; then the new rows are copied to the trigger table and to the inserted table.

Page 12: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert Trigger Example• When you insert a new foreign key row, make sure

the foreign key matches a primary key. The trigger should check for joins between the inserted rows (using the inserted table) and the rows in the primary key table, and then roll back any inserts of foreign keys that do not match a key in the primary key table.

• The following trigger compares the title_id values from the inserted table with those from the titles table. It assumes that you are making an entry for the foreign key and that you are not inserting a null value. If the join fails, the transaction is rolled back.

Page 13: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

PUBS2 DB Schema

Page 14: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert Trigger Examplecreate trigger forinsertrig1on salesdetailfor insertasif (select count(*)

from titles, insertedwhere titles.title_id = inserted.title_id) !=@@rowcount/* Cancel the insert and print a message.*/

beginrollback transactionprint ‘No, the title_id does not exist in titles.’

end/* Otherwise, allow it. */else

print ‘Added! All title_id’s exist in titles.’

Page 15: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert Trigger Example• @@rowcount (Returns the number of rows

affected by the last statement) refers to the number of rows added to the salesdetail table. This is also the number of rows added to the inserted table. The trigger joins titles and inserted to determine whether all the title_ids added to salesdetail exist in the titles table. If the number of joined rows, which is determined by the select count(*) query, differs from @@rowcount, then one or more of the inserts is incorrect, and the transaction is canceled.

Page 16: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert Trigger Example

• This trigger prints one message if the insert is rolled back and another if it is accepted. To test for the first condition, try this insert statement:

insert salesdetailvalues ("7066", "234517", "TC9999", 70, 45)To test for the second condition, enter:insert salesdetailvalues ("7896", "234518", "TC3218", 75, 80)

Page 17: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Delete Trigger Example• When you delete a primary key row, delete

corresponding foreign key rows in dependent tables. This preserves referential integrity by ensuring that detail rows are removed when their master row is deleted. If you do not delete the corresponding rows in the dependent tables, you may end up with a database with detail rows that cannot be retrieved or identified. To properly delete the dependent foreign key rows, use a trigger that performs a cascading delete.

Page 18: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Cascading Delete Example

• When a delete statement on titles is executed, one or more rows leave the titles table and are added to deleted. A trigger can check the dependent tables—titleauthor, salesdetail, and roysched—to see if they have any rows with a title_id that matches the title_ids removed from titles and is now stored in the deleted table. If the trigger finds any such rows, it removes them.

Page 19: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Cascading Delete Examplecreate trigger delcascadetrigon titlesfor deleteasdelete titleauthorfrom titleauthor, deletedwhere titleauthor.title_id = deleted.title_id/* Remove titleauthor rows that match deleted (titles) rows.*/delete salesdetailfrom salesdetail, deletedwhere salesdetail.title_id = deleted.title_id/* Remove salesdetail rows that match deleted ** (titles) rows.*/delete royschedfrom roysched, deletedwhere roysched.title_id = deleted.title_id/* Remove roysched rows that match deleted** (titles) rows.*/

Page 20: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Delete Examples

• In practice, you may want to keep some of the detail rows, either for historical purposes (to check how many sales were made on discontinued titles while they were active) or because transactions on the detail rows are not yet complete. A well-written trigger should take these factors into consideration.

Page 21: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Delete ExamplesPreventing primary key deletionsThe deltitle trigger prevents the deletion of a primary key if there are any detail rows for that key in the salesdetail table. This trigger preserves the ability to retrieve rows from salesdetail:

create trigger deltitleon titlesfor deleteasif (select count(*)

from deleted, salesdetailwhere salesdetail.title_id =deleted.title_id) > 0

beginrollback transactionprint ‘You cannot delete a title with sales.’

end

In this trigger, the row or rows deleted from titles are tested by being joinedwith the salesdetail table. If a join is found, the transaction is canceled.

Page 22: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Delete ExamplesRecording errors that occurThe following restricted delete prevents deletes if the primary table, titles, has dependent children in titleauthor. Instead of counting the rows from deleted and titleauthor, it checks to see if title_id was deleted. This method is more efficient for performance reasons because it checks for the existence of a particular row rather than going through the entire table and counting all the rows:create trigger restrict_dtrig on titlesfor delete asif exists (select * from titleauthor, deleted where titleauthor.title_id = deleted.title_id)begin

rollback transactionraiserror 35003return

endTo test this trigger, try this delete statement:delete titleswhere title_id = ‘PS2091’

Page 23: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Update Trigger ExamplesThe following example cascades an update from the primary table titles to the dependent tables titleauthor and roysched.create trigger cascade_utrigon titlesfor update asif update(title_id)beginupdate titleauthor

set title_id = inserted.title_id from titleauthor, deleted, insertedwhere deleted.title_id = titleauthor.title_id

update royschedset title_id = inserted.title_id from roysched, deleted, insertedwhere deleted.title_id = roysched.title_id

update salesdetailset title_id = inserted.title_id from salesdetail, deleted, insertedwhere deleted.title_id = salesdetail.title_id

end

Page 24: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Update Trigger ExamplesTo test this trigger, suppose that the book Secrets of Silicon Valley was reclassified to a psychology book from popular_comp. The following query updates the title_id PC8888 to PS8888 in titleauthor, roysched, and titles.update titlesset title_id = ‘PS8888’where title_id = ‘PC8888’

Page 25: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Update TriggersRestricted update trigger using date functions:The following trigger prevents updates to titles.title_id on the weekend. The if update clause in stopupdatetrig allows you to focus on a particular column, titles.title_id. Modifications to the data in that column cause the trigger to go into action. Changes to the data in other columns do not. When this trigger detects an update that violates the trigger conditions, it cancels the update and prints a message. If you would like to test this one, substitute the current day of the week for “Saturday” or “Sunday”.

Page 26: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Update TriggersRestricted update trigger using date functions:create trigger stopupdatetrigon titlesfor updateAs/* If an attempt is made to change titles.title_id** on Saturday or Sunday, cancel the update. */if update (title_id)

and datename(dw, getdate()) in ("Saturday", "Sunday") begin

rollback transactionprint ‘We do not allow changes to ‘print ‘primary keys on the weekend.’

end

Page 27: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Update Triggers

Restricted update triggers with multiple actions:You can specify multiple trigger actions on more than one column using if update. The following example modifies stopupdatetrig to include additional trigger actions for updates to titles.price or titles.advance. In addition to preventing updates to the primary key on weekends, it prevents updates to the price or advance of a title, unless the total revenue amount for that title surpasses its advance amount. You can use the same trigger name because the modified trigger replaces the old trigger when you create it again.

Page 28: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Restricted Update TriggersRestricted update triggers with multiple actions:create trigger stopupdatetrigon titlesfor updateasif update (title_id) and datename(dw, getdate()) in (‘Saturday’, ‘Sunday’)begin

rollback transactionPrint’We do not allow changes to’print ‘primary keys on the weekend!’

endif update (price) or update (advance)

if exists (select * from inserted where (inserted.price * inserted.total_sales) < inserted.advance) begin rollback transaction print ‘We do not allow changes to price or’ print ‘advance for a title until its total’ print ‘revenue exceeds its latest advance’

End

Page 29: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Multirow Considerations

Multirow considerations are particularly important when the function of a trigger is to recalculate summary values. Triggers are used to maintain summary values should contain group by clauses or subqueries that perform implicit grouping. This creates summary values when more than one row is being inserted, updated, or deleted. Since a group by clause imposes extra overhead, the following examples are written to test whether @@rowcount = 1, meaning that only one row in the trigger table was affected. If @@rowcount = 1, the trigger actions take effect without a group by clause.

Page 30: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert trigger example using multiple rows

The following insert trigger updates the total_sales column in the titles table every time a new salesdetail row is added. It goes into effect whenever you record a sale by adding a row to the salesdetail table. It updates the total_sales column in the titles table so that total_sales is equal to its previous value plus the value added to salesdetail.qty. This keeps the totals up to date for inserts into salesdetail.qty.

Page 31: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Insert trigger example using multiple rows

create trigger intrigon salesdetailfor insert as/* check value of @@rowcount */if @@rowcount = 1update titles

set total_sales = total_sales + qty

from insertedwhere titles.title_id =

inserted.title_idelse

/* when @@rowcount is greater than 1,use a group by clause */update titles

set total_sales =total_sales + (select

sum(qty)from insertedgroup by inserted.title_idhaving titles.title_id = inserted.title_id)

Page 32: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Delete trigger example using multiple rows

The next example is a delete trigger that updates the total_sales column in the titles table every time one or more salesdetail rows are deleted.

create trigger deltrigon salesdetailfor deleteas/* check value of @@rowcount */if @@rowcount = 1update titles

set total_sales = total_sales - qtyfrom deletedwhere titles.title_id =

deleted.title_id

.

Else /* when rowcount is greater than 1,use a group by clause */update titles

set total_sales = total_sales - (select sum(qty)

from deletedgroup by deleted.title_idhaving titles.title_id =

deleted.title_id)

This trigger goes into effect whenever a row is deleted from the salesdetail table. It updates the total_sales column in the titles table so that total_sales is equal to its previous value minus the value subtracted from salesdetail.qty.

Page 33: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Update trigger example using multiple rows

The following update trigger updates the total_sales column in the titles table every time the qty field in a salesdetail row is updated. Recall that an update is an insert followed by a delete. This trigger references both the inserted and the deleted trigger test tables.

Page 34: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Update trigger example using multiple rowscreate trigger updtrigon salesdetailfor updateasif update (qty)begin/* check value of @@rowcount */if @@rowcount = 1update titles set total_sales = total_sales + inserted.qty - deleted.qty from inserted, deleted where titles.title_id = inserted.title_idand inserted.title_id = deleted.title_idelse

/* when rowcount is greater than 1,use a group by clause */beginupdate titles set total_sales = total_sales + (select sum(qty)

from insertedgroup by inserted.title_idhaving titles.title_id =inserted.title_id)

update titlesset total_sales = total_sales - (select sum(qty)

from deletedgroup by deleted.title_idhaving titles.title_id =deleted.title_id)

endend

Page 35: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Nesting triggers

• Triggers can nest to a depth of 16 levels. The current nesting level is stored in the @@nestlevel global variable. Nesting is enabled at installation. A System Administrator can turn trigger nesting on and off with the allow nested triggers configuration parameter.

• If nested triggers are enabled, a trigger that changes a table on which there is another trigger fires the second trigger, which can in turn fire a third trigger, and so forth. If any trigger in the chain sets off an infinite loop, the nesting level is exceeded and the trigger aborts. You can use nested triggers to perform useful housekeeping functions such as storing a backup copy of rows affected by a previous trigger.

Page 36: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Nesting triggers

• For example, you can create a trigger on titleauthor that saves a backup copy of titleauthor rows that was deleted by the delcascadetrig trigger. With the delcascadetrig trigger in effect, deleting the title_id “PS2091” from titles also deletes the corresponding row(s) from titleauthor. To save the data, you can create a delete trigger on titleauthor that saves the deleted data in another table, del_save:

create trigger savedelon titleauthorfor deleteasinsert del_saveselect * from deleted

Page 37: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Using INSTEAD OF Triggers • The idea behind an INSTEAD OF trigger is that it fires

instead of the INSERT, UPDATE, or DELETE statement that triggers it. Plus, you can define these triggers on views.

• In other words, views that would normally not be can have their underlying tables updated in an updatable INSTEAD OF trigger.

• An INSTEAD OF trigger can support inserts, updates, and deletes that reference data in more than one table, and can also allow you to code more complex logic that will be applied whenever the view or table is modified.

• You could present a friendly interface through a view and behind the scenes any updates to that simple view could be propagated to many different underlying tables.

Page 38: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Using INSTEAD OF Triggers • For example, a view containing a join between the products and the categories

tables would normally only allow you to update either one or the other in a single UPDATE statement, not both:

CREATE VIEW vwProductByCategoryItrig AS SELECT C.Category, P.ProductID, P.Product FROM tblProduct AS P INNER JOIN tblCategory AS C ON P.CategoryID = C.CategoryID Try executing this update and you’ll get an error: UPDATE vwProductByCategoryItrig SET Product = 'Shark Thingys', Category = 'Thingys' WHERE ProductID = 1

Page 39: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Using INSTEAD OF Triggers The following INSTEAD OF trigger independently updates each table anytime an attempt is made to update the view. The trigger takes over and performs two separate updates instead of letting things take their course and attempting a single illegal update:

CREATE TRIGGER trigUpdateBoth ON vwProductByCategoryItrig INSTEAD OF UPDATE AS SET NOCOUNT ON UPDATE tblProduct SET tblProduct.Product = (SELECT inserted.Product FROM inserted) WHERE tblProduct.ProductID = (SELECT inserted.ProductID FROM inserted) UPDATE tblCategory SET tblCategory.Category = (SELECT inserted.Category FROM inserted) WHERE tblCategory.Category = (SELECT deleted.Category FROM deleted)

Page 40: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Using INSTEAD OF Triggers Although a single UPDATE statement that tried to update both the Product and the Category tables through a view would otherwise fail, the INSTEAD OF trigger fires instead of the normal UPDATE statement and explicitly writes changes back to both tables. The user or client application doesn’t even have to know what the underlying tables are or how they are related. The update statement will now succeed.

UPDATE vwProductByCategoryItrig SET Product = 'Shark Thingys', Category = 'Thingys' WHERE ProductID = 1

Page 41: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Rules associated with triggersTriggers and permissions: A trigger is defined on a particular table. Only the owner of the table has create trigger and drop trigger permissions for the table. These permissions cannot be transferred to others.For example, Jose owns salesdetail and creates a trigger on it. The trigger is supposed to update titles.total_sales when salesdetail.qty is updated. However, Mary is the owner of titles, and has not granted Jose permission on titles. When Jose tries to update salesdetail, Server detects the trigger and Jose’s lack of permissions on titles, and rolls back the update transaction. Jose must either get update permission on titles.total_sales from Mary or drop the trigger on salesdetail.

Page 42: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Disabling triggersThe insert, update, and delete commands normally fire any trigger they encounter, which increases the time needed to perform the operation. To disable triggers during bulk insert, update, or delete operations, you can use the disable trigger option of the alter table command. You can use the disable trigger option either to disable all the triggers associated with the table, or to specify a particular trigger to disable. However, any triggers you disable will not be fired after the copy is complete. For example:

alter table [database_name.[owner_name].]table_name{enable | disable } trigger [trigger_name]

Disablealter table pubs2disable del_pubsEnable:alter table pubs2enable del_pubs

Page 43: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Dropping triggersYou can remove a trigger by dropping it or by dropping the trigger table with which it is associated.The drop trigger syntax is:drop trigger [owner.]trigger_name [, [owner.]trigger_name]...

When you drop a table, Server drops any triggers associated with it. drop trigger permission defaults to the trigger table owner and is not transferable.

Page 44: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Getting information about triggersAs database objects, triggers are listed in sysobjects by name. The type column of sysobjects identifies triggers with the abbreviation “TR”. This query finds the triggers that exist in a database:select *from sysobjectswhere type = "TR"The source text for each trigger is stored in syscomments. Execution plans for triggers are stored in sysprocedures. The system procedures described in the following sections provide information from the system tables about triggers.

Page 45: Triggers How triggers work Creating triggers Using triggers to maintain referential integrity Multirow considerations Nesting triggers Rules associated

Getting information about triggerssp_help: You can get a report on a trigger using sp_help. For example, you can get information on deltitle as follows:sp_help deltitlesp_helptext: To display the source text of a trigger, execute sp_helptext, as follows:sp_helptext deltitlesp_depends: lists the triggers that reference an object or all the tables or views that the trigger affects. This example shows how to use sp_depends to get a list of all the objects referenced by the trigger deltitle:sp_depends deltitle