A trigger is a task that executes in response to some predefined database event, such as after a new row is added to a particular table. Specifically, this event involves inserting, modifying, or deleting table data, and the task can occur either prior to or immediately following any such event. This chapter begins by offering general examples that illustrate how you can use triggers to carry out tasks such as enforcing referential integrity and business rules, gathering statistics, and preventing invalid transactions. I will then discuss MySQL’s trigger implementation, showing you how to create, execute, and manage triggers. Finally, you’ll learn how to incorporate trigger features into your PHP-driven web applications.
Introducing Triggers
Preventing corruption due to malformed data.
Enforcing business rules, such as ensuring that an attempt to insert information about a product into the product table includes the identifier of a manufacturer whose information already resides in the manufacturer table.
Ensuring database integrity by cascading changes throughout a database, such as removing all products associated with a manufacturer that you’d like to remove from the system.
If you’ve built even a simple application, you’ve likely spent some time writing code to carry out at least some of these tasks. When possible, it’s preferable to carry out some of these tasks automatically on the server side, regardless of which type of application is interacting with the database. Database triggers give you that choice.
Why Use Triggers?
Audit trails : Suppose you are using MySQL to log Apache traffic (possibly using the Apache mod_log_sql module) but you also want to create an additional special logging table that lets you quickly tabulate and display the results to an impatient executive. Executing this additional insertion can be done automatically with a trigger.
Validation : You can use triggers to validate data before updating the database, such as to ensure that a minimum-order threshold has been met.
Referential integrity enforcement : Sound database administration practice dictates that table relationships remain stable throughout the lifetime of a project. Rather than attempt to incorporate all integrity constraints programmatically, it occasionally may make sense to use triggers to ensure that these tasks occur automatically. Databases that supports foreign key constraints can handle integrity enforcements without triggers. Maintaining referential integrity means making sure no reference points to a record in another (or the same) table if that record is deleted. Foreign key is the term used for a column that identifies a key from another table and thus links the two tables together.
The utility of triggers stretches far beyond these purposes. Suppose you want to update the corporate website when the $1 million monthly revenue target is met. Or suppose you want to e-mail any employee who misses more than two days of work in a week. Or perhaps you want to notify a manufacturer when inventory runs low on a particular product. All of these tasks can be handled by triggers.
To provide you with a better idea of the utility of triggers, let’s consider two scenarios: the first involving a before trigger, a trigger that occurs prior to an event; and the second involving an after trigger, a trigger that occurs after an event.
Taking Action Before an Event
Taking Action After an Event
Most helpdesk support software is based upon the notion of ticket assignment and resolution. Tickets are both assigned to and resolved by helpdesk technicians, who are responsible for logging ticket information. However, occasionally even the technicians are allowed out of their cubicle to take a vacation or recover from an illness. Clients can’t be expected to wait for the technician to return during such absences, so the technician’s tickets should be placed back in the pool for reassignment by the manager.
This process should be automatic so that outstanding tickets aren’t potentially ignored. This is a great scenario in which to use a trigger.
Later in this chapter, you’ll learn how to implement this trigger and incorporate it into a web application.
Before Triggers vs. After Triggers
You may be wondering how one arrives at the conclusion to use a before trigger in lieu of an after trigger. For example, in the after-trigger scenario in the previous section, why couldn’t the ticket reassignment take place prior to the change to the technician’s availability status? Standard practice dictates that you should use a before trigger when validating or modifying data that you intend to insert or update. A before trigger shouldn’t be used to enforce propagation or referential integrity (making sure all keys points to existing records in other tables), because it’s possible that other before triggers could execute after it, meaning the executing trigger may be working with soon-to-be-invalid data.
On the other hand, an after trigger should be used when data is to be propagated or verified against other tables, and for carrying out calculations, because you can be sure the trigger is working with the final version of the data.
In the following sections, you’ll learn how to create, manage, and execute MySQL triggers most effectively. Numerous examples involving trigger usage in PHP/MySQL-driven applications are also presented.
MySQL’s Trigger Support
TEMPORARY tables are not supported: A trigger can’t be used in conjunction with a TEMPORARY table.
Views are not supported: A trigger can’t be used in conjunction with a view (introduced in the next chapter).
The MySQL database does not allow triggers: Tables created in the mysql database will not allow creation of triggers.
Result sets can’t be returned from a trigger: It’s only possible to execute INSERT, UPDATE, and DELETE queries within a trigger. You can, however, execute stored routines within a trigger, provided they don’t return result sets, as well as the SET command.
Triggers must be unique: It’s not possible to create multiple triggers sharing the same table, event (INSERT, UPDATE, DELETE), and cue (before, after). However, because multiple commands can be executed within the boundaries of a single query (as you’ll soon learn), this shouldn’t really present a problem.
Error handling and reporting support is immature: Although, as expected, MySQL will prevent an operation from being performed if a before or after trigger fails, there is presently no graceful way to cause the trigger to fail and return useful information to the user.
This might seem limiting, but triggers still provide a powerful way of implementing business logic. If you have multiple users/systems interacting directly with the database and you don’t want each of them to implement certain business logic, you can use triggers. A different way to solve this is to create APIs where the logic is implemented and only allow the users to interact with the API and not directly with the database. An advantage of this approach is the freedom you get to alter the schema when needed as long as your API continues to work the same way.
Creating a Trigger
As you can see, it’s possible to specify whether the trigger should execute before or after the query; whether it should take place on row insertion, modification, or deletion; and to what table the trigger applies.
The DEFINER clause determines which user account will be consulted to determine whether appropriate privileges are available to execute the queries defined within the trigger. If defined, you’ll need to specify both the username and hostname using 'user@host' syntax (for example, 'jason@localhost'). If CURRENT_USER is used (the default), then the privileges of whichever account has caused the trigger to execute will be consulted. Only users having the SUPER privilege are able to assign DEFINER to another user.
Note
You may be wondering about the au prefix in the trigger title. See the sidebar “Trigger Naming Conventions” for more information about this and similar prefixes.
For each row affected by an update to the technicians table, the trigger will update the tickets table, setting tickets.technician_id to null wherever the technician_id value specified in the UPDATE query exists. You know the query value is being used because the alias NEW prefixes the column name. It’s also possible to use a column’s original value by prefixing it with the OLD alias .
Now check the tickets table, and you’ll see that both tickets that were assigned to Jason are assigned no longer.
Trigger Naming Conventions
ad: Execute trigger after a DELETE query has taken place
ai: Execute trigger after an INSERT query has taken place
au: Execute trigger after an UPDATE query has taken place
bd: Execute trigger before a DELETE query has taken place
bi: Execute trigger before an INSERT query has taken place
bu: Execute trigger before an UPDATE query has taken place
Viewing Existing Triggers
It’s possible to view existing triggers in one of two ways: by using the SHOW TRIGGERS command or by using the information schema. Both solutions are introduced in this section.
The SHOW TRIGGERS Command
An alternative approach to learning more about a trigger involves querying the INFORMATION_SCHEMA database.
The INFORMATION_SCHEMA
Modifying a Trigger
At the time of writing, there was no supported command or GUI application available for modifying an existing trigger. Therefore, perhaps the easiest strategy for modifying a trigger is to delete and subsequently re-create it.
Deleting a Trigger
You need the TRIGGER or SUPER privilege to successfully execute DROP TRIGGER.
Caution
When a database or table is dropped, all corresponding triggers are also deleted.
Create trigger
Integrating Triggers into Web Applications
Because triggers occur transparently, you really don’t need to do anything special to integrate their operation into your web applications. Nonetheless, it’s worth offering an example demonstrating just how useful this feature can be in terms of both decreasing the amount of PHP code and further simplifying the application logic. In this section, you’ll learn how to implement the helpdesk application first depicted earlier in the “Taking Action After an Event” section.
To begin, if you haven’t done so already, go ahead and create the two tables (technicians and tickets) depicted in the earlier section. Add a few appropriate rows to each, making sure that each tickets.technician_id matches a valid technicians.technician_id. Next, create the au_reassign_ticket trigger as previously described.
Updating the Technician Profile
Once this code has been executed , return to the tickets table and you’ll see that the relevant tickets have been unassigned.
Summary
Triggers can greatly reduce the amount of code you need to write solely for ensuring the referential integrity and business rules of your database. You learned about the different trigger types and the conditions under which they will execute. An introduction to MySQL’s trigger implementation was offered, followed by coverage of how to integrate these triggers into your PHP applications.
The next chapter introduces views, a powerful feature that allows you to essentially create easy-to-remember aliases for otherwise long and complex SQL statements.