Database trigger

Last updated

A database trigger is procedural code that is automatically executed in response to certain events on a particular table or view in a database. The trigger is mostly used for maintaining the integrity of the information on the database. For example, when a new record (representing a new worker) is added to the employees table, new records should also be created in the tables of the taxes, vacations and salaries. Triggers can also be used to log historical data, for example to keep track of employees' previous salaries.

Contents

Triggers in DBMS

Below follows a series of descriptions of how some popular DBMS support triggers.

Oracle

In addition to triggers that fire (and execute PL/SQL code) when data is modified, Oracle 10g supports triggers that fire when schema-level objects (that is, tables) are modified and when user logon or logoff events occur.

Schema-level triggers

  • After Creation
  • Before Alter
  • After Alter
  • Before Drop
  • After Drop
  • Before Insert

The four main types of triggers are:

  1. Row-level trigger: This gets executed before or after any column value of a row changes
  2. Column-level trigger: This gets executed before or after the specified column changes
  3. For each row type: This trigger gets executed once for each row of the result set affected by an insert/update/delete
  4. For each statement type: This trigger gets executed only once for the entire result set, but also fires each time the statement is executed.

System-level triggers

From Oracle 8i, database events - logons, logoffs, startups - can fire Oracle triggers. [1]

Microsoft SQL Server

A list of all available firing events in Microsoft SQL Server for DDL triggers is available on Microsoft Docs. [2]

Performing conditional actions in triggers (or testing data following modification) is done through accessing the temporary Inserted and Deleted tables.

PostgreSQL

Introduced support for triggers in 1997. The following functionality in SQL:2003 was previously not implemented in PostgreSQL:

Synopsis:

CREATETRIGGERname{BEFORE|AFTER}{event[OR...]}ONTABLE[FOR[EACH]{ROW|STATEMENT}]EXECUTEPROCEDUREfuncname(arguments)

Firebird

Firebird supports multiple row-level, BEFORE or AFTER, INSERT, UPDATE, DELETE (or any combination of thereof) triggers per table, where they are always "in addition to" the default table changes, and the order of the triggers relative to each other can be specified where it would otherwise be ambiguous (POSITION clause.) Triggers may also exist on views, where they are always "instead of" triggers, replacing the default updatable view logic. (Before version 2.1, triggers on views deemed updatable would run in addition to the default logic.)

Firebird does not raise mutating table exceptions (like Oracle), and triggers will by default both nest and recurse as required (SQL Server allows nesting but not recursion, by default.) Firebird's triggers use NEW and OLD context variables (not Inserted and Deleted tables,) and provide UPDATING, INSERTING, and DELETING flags to indicate the current usage of the trigger.

{CREATE|RECREATE|CREATEORALTER}TRIGGERnameFOR{tablename|viewname}[ACTIVE|INACTIVE]{BEFORE|AFTER}{INSERT[ORUPDATE][ORDELETE]|UPDATE[ORINSERT][ORDELETE]|DELETE[ORUPDATE][ORINSERT]}[POSITIONn]ASBEGIN....END

As of version 2.1, Firebird additionally supports the following database-level triggers:

Database-level triggers can help enforce multi-table constraints, or emulate materialized views. If an exception is raised in a TRANSACTION COMMIT trigger, the changes made by the trigger so far are rolled back and the client application is notified, but the transaction remains active as if COMMIT had never been requested; the client application can continue to make changes and re-request COMMIT.

Syntax for database triggers:

{CREATE|RECREATE|CREATEORALTER}TRIGGERname[ACTIVE|INACTIVE]ON{CONNECT|DISCONNECT|TRANSACTIONSTART|TRANSACTIONCOMMIT|TRANSACTIONROLLBACK}[POSITIONn]ASBEGIN.....END

MySQL/MariaDB

Limited support for triggers in the MySQL/MariaDB DBMS was added in the 5.0 version of MySQL, launched in 2005. [4]

As of version 8.0, they allow for DDL (Data Definition Language) triggers and for DML (Data Manipulation Language) triggers. They also allow either type of DDL trigger (AFTER or BEFORE) to be used to define triggers. They are created by using the clause CREATE TRIGGER and deleted by using the clause DROP TRIGGER. The statement called upon an event happens is defined after the clause FOR EACH ROW, followed by a keyword (SET or BEGIN), which indicates whether what follows is an expression or a statement respectively. [5]

IBM DB2 LUW

IBM DB2 for distributed systems known as DB2 for LUW (LUW means Linux, Unix, Windows) supports three trigger types: Before trigger, After trigger and Instead of trigger. Both statement level and row level triggers are supported. If there are more triggers for same operation on table then firing order is determined by trigger creation data. Since version 9.7 IBM DB2 supports autonomous transactions. [6]

Before trigger is for checking data and deciding if operation should be permitted. If exception is thrown from before trigger then operation is aborted and no data are changed. In DB2 before triggers are read only — you can't modify data in before triggers. After triggers are designed for post processing after requested change was performed. After triggers can write data into tables and unlike some[ which? ] other databases you can write into any table including table on which trigger operates. Instead of triggers are for making views writeable.

Triggers are usually programmed in SQL PL language.

SQLite

CREATE[TEMP|TEMPORARY]TRIGGER[IFNOTEXISTS][database_name.]trigger_name[BEFORE|AFTER|INSTEADOF]{DELETE|INSERT|UPDATE[OFcolumn_name[,column_name]...]}ON{table_name|view_name}[FOREACHROW][WHENconditionismandatory]BEGIN...END

SQLite only supports row-level triggers, not statement-level triggers.

Updateable views, which are not supported in SQLite, can be emulated with INSTEAD OF triggers.

XML databases

An example of implementation of triggers in non-relational database can be Sedna, that provides support for triggers based on XQuery. Triggers in Sedna were designed to be analogous to SQL:2003 triggers, but natively base on XML query and update languages (XPath, XQuery and XML update language).

A trigger in Sedna is set on any nodes of an XML document stored in database. When these nodes are updated, the trigger automatically executes XQuery queries and updates specified in its body. For example, the following trigger cancels person node deletion if there are any open auctions referenced by this person:

CREATETRIGGER"trigger3"BEFOREDELETEONdoc("auction")/site//personFOREACHNODEDO{if(exists($WHERE//open_auction/bidder/personref/@person=$OLD/@id))then()else$OLD;}

Row and statement level triggers

To understand how trigger behavior works, you need to be aware of the two main types of triggers; these are Row and Statement level triggers. The distinction between the two is how many times the code within the trigger is executed, and at what time.

Suppose you have a trigger that is made to be called on an UPDATE to a certain table. Row level triggers would execute once for each row that is affected by the UPDATE. It is important to keep in mind if no rows are affected by the UPDATE command, the trigger will not execute any code within the trigger. Statement level triggers will be called once regardless of how many rows are affected by the UPDATE. Here it is important to note that even if the UPDATE command didn't affect any rows, the code within the trigger will still be executed once.

Using the BEFORE and AFTER options [7] determine when the trigger is called. Suppose you have a trigger that is called on an INSERT to a certain table. If your trigger is using the BEFORE option, the code within the trigger will be executed before the INSERT into the table occurs. A common use of the BEFORE trigger is to verify the input values of the INSERT, or modify the values accordingly. Now let's say we have a trigger that uses AFTER instead. The code within the trigger is executed after the INSERT happens to the table. An example use of this trigger is creating an audit history of who has made inserts into the database, keeping track of the changes made. When using these options you need to keep a few things in mind. The BEFORE option does not allow you to modify tables, that is why input validation is a practical use. Using AFTER triggers allows you to modify tables such as inserting into an audit history table.

When creating a trigger to determine if it is statement or row level simply include the FOR EACH ROW clause for a row level, or omit the clause for a statement level. Be cautious of using additional INSERT/UPDATE/DELETE commands within your trigger, because trigger recursion is possible, causing unwanted behavior. In the examples below each trigger is modifying a different table, by looking at what is being modified you can see some common applications of when different trigger types are used.

The following is an Oracle syntax example of a row level trigger that is called AFTER an update FOR EACH ROW affected. This trigger is called on an update to a phone book database. When the trigger is called it adds an entry into a separate table named phone_book_audit. Also take note of triggers being able to take advantage of schema objects like sequences, [8] in this example audit_id_sequence.nexVal is used to generate unique primary keys in the phone_book_audit table.

CREATEORREPLACETRIGGERphone_book_auditAFTERUPDATEONphone_bookFOREACHROWBEGININSERTINTOphone_book_audit(audit_id,audit_change,audit_l_name,audit_f_name,audit_old_phone_number,audit_new_phone_number,audit_date)VALUES(audit_id_sequence.nextVal,'Update',:OLD.last_name,:OLD.first_name,:OLD.phone_number,:NEW.phone_number,SYSDATE);END;

Now calling an UPDATE on the phone_book table for people with the last name 'Jones'.

UPDATEphone_bookSETphone_number='111-111-1111'WHERElast_name='Jones';
Audit_IDAudit_ChangeF_NameL_NameNew_Phone_NumberOld_Phone_NumberAudit_Date
1UpdateJordanJones111-111-1111098-765-432102-MAY-14
2UpdateMeganJones111-111-1111111-222-345602-MAY-14


Notice that the phone_number_audit table is now populated with two entries. This is due to the database having two entries with the last name of 'Jones'. Since the update modified two separate row values, the created trigger was called twice; once after each modification.

After - statement-level trigger

An Oracle syntax statement trigger that is called after an UPDATE to the phone_book table. When the trigger gets called it makes an insert into phone_book_edit_history table

CREATEORREPLACETRIGGERphone_book_historyAFTERUPDATEONphone_bookBEGININSERTINTOphone_book_edit_history(audit_history_id,username,modification,edit_date)VALUES(audit_history_id_sequence.nextVal,USER,'Update',SYSDATE);END;

Now doing exactly the same update as the above example, however this time with a statement level trigger.

UPDATEphone_bookSETphone_number='111-111-1111'WHERElast_name='Jones';
Audit_History_IDUsernameModificationEdit_Date
1HAUSCHBCUpdate02-MAY-14

The result shows that the trigger was only called once, even though the update did change two rows.

Before each - row-level trigger

This example demonstrates a BEFORE EACH ROW trigger that modifies the INSERT using a WHEN conditional. If the last name is larger than 10 letters, using the SUBSTR function [9] we change the last_name column value to an abbreviation.

CREATEORREPLACETRIGGERphone_book_insertBEFOREINSERTONphone_bookFOREACHROWWHEN(LENGTH(new.last_name)>10)BEGIN:new.last_name:=SUBSTR(:new.last_name,0,1);END;

Now performing an INSERT of someone with a large name.

INSERTINTOphone_bookVALUES(6,'VeryVeryLongLastName','Erin','Minneapolis','MN','989 University Drive','123-222-4456',55408,TO_DATE('11/21/1991','MM/DD/YYYY'));
Person_IDLast_NameFirst_NameCityState_AbbreviationAddressPhone_NumberZip_codeDOB
6VErinMinneapolisMN989 University Drive123-222-44565540821-NOV-91

The trigger worked as per the result above, modifying the value of the INSERT before it was executed.

Before - statement-level trigger

Using a BEFORE statement trigger is particularly useful when enforcing database restrictions. [10] This example demonstrate how to enforce a restriction upon someone named "SOMEUSER" on the table phone_book.

CREATEORREPLACETRIGGERhauschbcBEFOREINSERTONSOMEUSER.phone_bookBEGINRAISE_APPLICATION_ERROR(num=>-20050,msg=>'Error message goes here.');END;

Now, when "SOMEUSER" is logged in after attempting any INSERT this error message will show:

SQL Error: ORA-20050: Error message goes here.

Custom errors such as this one has a restriction on what the num variable can be defined as. Because of the numerous other pre-defined errors this variable must be in the range of −20000 to −20999.

Related Research Articles

A foreign key is a set of attributes in a table that refers to the primary key of another table. The foreign key links these two tables. Another way to put it: In the context of relational databases, a foreign key is a set of attributes subject to a certain kind of inclusion dependency constraints, specifically a constraint that the tuples consisting of the foreign key attributes in one relation, R, must also exist in some other relation, S, and furthermore that those attributes must also be a candidate key in S. In simpler words, a foreign key is a set of attributes that references a candidate key. For example, a table called TEAM may have an attribute, MEMBER_NAME, which is a foreign key referencing a candidate key, PERSON_NAME, in the PERSON table. Since MEMBER_NAME is a foreign key, any value existing as the name of a member in TEAM must also exist as a person's name in the PERSON table; in other words, every member of a TEAM is also a PERSON.

A stored procedure is a subroutine available to applications that access a relational database management system (RDBMS). Such procedures are stored in the database data dictionary.

Transact-SQL (T-SQL) is Microsoft's and Sybase's proprietary extension to the SQL used to interact with relational databases. T-SQL expands on the SQL standard to include procedural programming, local variables, various support functions for string processing, date processing, mathematics, etc. and changes to the DELETE and UPDATE statements.

In the context of SQL, data definition or data description language (DDL) is a syntax for creating and modifying database objects such as tables, indices, and users. DDL statements are similar to a computer programming language for defining data structures, especially database schemas. Common examples of DDL statements include CREATE, ALTER, and DROP.

An SQL INSERT statement adds one or more records to any single table in a relational database.

A data manipulation language (DML) is a computer programming language used for adding (inserting), deleting, and modifying (updating) data in a database. A DML is often a sublanguage of a broader database language such as SQL, with the DML comprising some of the operators in the language. Read-only selecting of data is sometimes distinguished as being part of a separate data query language (DQL), but it is closely related and sometimes also considered a component of a DML; some operators may perform both selecting (reading) and writing.

A data control language (DCL) is a syntax similar to a computer programming language used to control access to data stored in a database (authorization). In particular, it is a component of Structured Query Language (SQL). Data Control Language is one of the logical group in SQL Commands. SQL is the standard language for relational database management systems. SQL statements are used to perform tasks such as insert data to a database, delete or update data in a database, or retrieve data from a database.

The following tables compare general and technical information for a number of relational database management systems. Please see the individual products' articles for further information. Unless otherwise specified in footnotes, comparisons are based on the stable versions without any add-ons, extensions or external programs.

A user-defined function (UDF) is a function provided by the user of a program or environment, in a context where the usual assumption is that functions are built into the program or environment. UDFs are usually written for the requirement of its creator.

In a database, a view is the result set of a stored query, which can be queried in the same manner as a persistent database collection object. This pre-established query command is kept in the data dictionary. Unlike ordinary base tables in a relational database, a view does not form part of the physical schema: as a result set, it is a virtual table computed or collated dynamically from data in the database when access to that view is requested. Changes applied to the data in a relevant underlying table are reflected in the data shown in subsequent invocations of the view.

In computer science, a database cursor is a mechanism that enables traversal over the records in a database. Cursors facilitate subsequent processing in conjunction with the traversal, such as retrieval, addition and removal of database records. The database cursor characteristic of traversal makes cursors akin to the programming language concept of iterator.

In SQL, the TRUNCATE TABLE statement is a Data Definition Language (DDL) operation that deletes all rows of a table without causing a triggered action. The result of this operation quickly removes all data from a table, typically bypassing a number of integrity enforcing mechanisms. It was officially introduced in the SQL:2008 standard, as the optional feature F200, "TRUNCATE TABLE statement".

A check constraint is a type of integrity constraint in SQL which specifies a requirement that must be met by each row in a database table. The constraint must be a predicate. It can refer to a single column, or multiple columns of the table. The result of the predicate can be either TRUE, FALSE, or UNKNOWN, depending on the presence of NULLs. If the predicate evaluates to UNKNOWN, then the constraint is not violated and the row can be inserted or updated in the table. This is contrary to predicates in WHERE clauses in SELECT or UPDATE statements.

Gadfly is a relational database management system written in Python. Gadfly is a collection of Python modules that provides relational database functionality entirely implemented in Python. It supports a subset of the standard RDBMS Structured Query Language (SQL).

A hierarchical query is a type of SQL query that handles hierarchical model data. They are special cases of more general recursive fixpoint queries, which compute transitive closures.

Java Database Connectivity (JDBC) is an application programming interface (API) for the Java programming language which defines how a client may access a database. It is a Java-based data access technology used for Java database connectivity. It is part of the Java Standard Edition platform, from Oracle Corporation. It provides methods to query and update data in a database, and is oriented toward relational databases. A JDBC-to-ODBC bridge enables connections to any ODBC-accessible data source in the Java virtual machine (JVM) host environment.

In relational databases, the log trigger or history trigger is a mechanism for automatic recording of information about changes inserting or/and updating or/and deleting rows in a database table.

In database management systems (DBMS), a prepared statement, parameterized statement, or parameterized query is a feature where the database pre-compiles SQL code and stores the results, separating it from data. Benefits of prepared statements are:

PL/SQL is Oracle Corporation's procedural extension for SQL and the Oracle relational database. PL/SQL is available in Oracle Database, Times Ten in-memory database, and IBM Db2. Oracle Corporation usually extends PL/SQL functionality with each successive release of the Oracle Database.

The syntax of the SQL programming language is defined and maintained by ISO/IEC SC 32 as part of ISO/IEC 9075. This standard is not freely available. Despite the existence of the standard, SQL code is not completely portable among different database systems without adjustments.

References

  1. Nanda, Arup; Burleson, Donald K. (2003). "9". In Burleson, Donald K. (ed.). Oracle Privacy Security Auditing: Includes Federal Law Compliance with HIPAA, Sarbanes Oxley and the Gramm Leach Bliley Act GLB. Oracle in-focus series. Vol. 47. Kittrell, North Carolina: Rampant TechPress. p. 511. ISBN   9780972751391 . Retrieved 2018-04-17. [...] system-level triggers [...] were introduced in Oracle8i. [...] system-level triggers are fired at specific system events such as logon, logoff, database startup, DDL execution, and servererror [...].
  2. "DDL Events - SQL Server".
  3. "PostgreSQL: Documentation: 9.0: CREATE TRIGGER". www.postgresql.org. 8 October 2015.
  4. MySQL 5.0 Reference Manual. "Triggers. MySQL 5.0 added limited support for triggers", Oracle Corporation , Retrieved on 4 March 2020.
  5. "MySQL :: MySQL 8.0 Reference Manual :: 25.3.1 Trigger Syntax and Examples".
  6. "Autonomous transactions". www.ibm.com. July 30, 2009.
  7. "6 Using Triggers". docs.oracle.com.
  8. "Oracle's Documentation on Sequences". Archived from the original on 2011-12-01.
  9. "Oracle SQL Functions – The Complete List". December 26, 2014.
  10. "Database PL/SQL Language Reference". docs.oracle.com.