Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
MySQL 5 Stored Procedures, Triggers and Views - An Article by Larkin Cunningham
1. SYSADMIN MySQL 5
Stored procedures, triggers, and views in MySQL 5
THE SEQUEL
We’ll show you how some new features of MySQL 5 will improve
software design and boost application performance.
BY LARKIN CUNNINGHAM
T
he open source MySQL database troduced in version 5.0, and some may will no doubt continue to improve with
system serves many of the be enhanced in version 5.1, which is in later versions of MySQL.
world’s leading enterprises, such beta at this time of writing but may be
The Ordering Scenario
as Yahoo and Ticketmaster. It also pow- official by the time you read this article. I
ers a legion of high volume open source used version 5.1.9-beta when testing the Throughout this article I will refer to a
websites like Wikipedia. Many enter- listings in this article. products table, an order_headers table,
prise organizations, however, have tradi- Three of the most appealing new fea- an order_lines table, a stock_quantities
tionally avoided MySQL in favor of fea- tures in MySQL 5.x are stored proce- table and a customers table for the pur-
ture-rich commercial database systems, dures, triggers, and views. These fea- poses of illustration. Listing 1 shows the
such as Oracle and DB2. Starting with tures are hardly new for the industry. Or- SQL create table statements that create
MySQL 5.0 [1], the MySQL developers acle, for example, first introduced PL/ the tables. When giving examples of
have begun introducing a range of enter- SQL [2], its implementation of a proce- stored procedures, triggers, and views, I
prise features that will ultimately make dural language for SQL, in 1991. Sybase, will refer to the tables in the listing.
MySQL more competitive with commer- PostgreSQL, and DB2 are among the
Stored Procedures
cial database systems. This article exam- other database management systems
ines some of the enterprise features that with a procedural language for SQL. Before explaining what stored proce-
have been making their way into However, triggers, views, and stored pro- dures are, I should explain that when I
MySQL. Many of these features were in- cedures are nevertheless a welcome ad- use the term stored procedure, I am usu-
dition to MySQL. ally referring to both stored procedures
I should point out that some of these and stored functions. A stored procedure
THE AUTHOR
Larkin Cunningham just loves open
source software. Soon to begin re- MySQL enterprise features are in early accepts multiple input and output pa-
searching towards a PhD, Larkin stages of development. Many of these rameters. A stored function also accepts
currently works with Oracle PL/SQL features are either incomplete or not per- multiple input parameters but returns a
and Java, but finds time to dabble in forming at optimum levels. Version 5.1 single value to the caller. This restriction
all things Linux. He can be contacted
has addressed some of the issues related allows stored functions to be used
at larkin.cunningham@gmail.com.
to these new features, and the situation within SQL statements, which effectively
52 ISSUE 69 AUGUST 2006 W W W. L I N U X - M A G A Z I N E . C O M
2. SYSADMIN
MySQL 5
allows you to extend the capability of warrant dedicated development re- heterogeneous environment with many
SQL. sources. development platforms, then using
Stored procedures are a powerful tool Portability is also aided by developing stored procedures may be a way for you
to have in a developer’s arsenal. They more of your logic within the database. to develop your data processing logic
can be of great benefit in terms of perfor- It would be possible, for example, to de- once in a central location. After all,
mance and application design. In terms velop a batch application using C, a web stored procedures do not care what pro-
of performance, it is possible to reduce a application using Ruby on Rails, and a gramming language makes the call.
lot of network traffic by performing more web service developed using Java, and
Triggers
data processing within the confines of have them all using the same set of
the database. By reducing network traf- stored procedures. Triggers have many uses, including
fic, you can eliminate the latency associ- The approach of many to developing house-keeping jobs like auditing and ar-
ated with the application server commu- applications that use a relational data- chival. They can have many other uses
nicating with the database server, partic- base is to either embed all of the SQL too. One common scenario is where a
ularly when they are on separate servers, within their code or to embed all of the trigger is fired (more on trigger timing
as is the case with most large scale ap- SQL in stored procedures and only call and firing later) after a row is created,
plications. stored procedures from their code. Many for example an order line being added to
With stored procedures you can take a developers rely on object-relational map- the order_lines table. A trigger could be
black box approach to application design pers such as Hibernate [3] (for Java) and fired after the row is inserted to update
and development. A developer program- ActiveRecord [4] (for Ruby on Rails), the stock quantity of the product in the
ming in Java, PHP, Ruby, or any other where stored procedures are largely irrel- stock_quantities table.
language with MySQL driver support evant. Deciding on your approach to Where archiving is required, you can
does not need to have extensive knowl- how to handle data processing in your have an additional archive table for each
edge of SQL or PL/SQL. On a multi- applications will depend on factors such table where you want to store archive in-
member development team, you can as performance and portability. If perfor- formation. For example, the products
have stored procedure developers con- mance is not a concern, then you would table may have an associated products_
centrating on stored procedure develop- be in a position to consider an object-re- archive table with all of the same col-
ment and Java, PHP or Ruby developers lational mapper that generates your SQL umns as the products table. To automati-
concentrating on their particular pro- on the fly. But if you care about perfor- cally archive, you would create triggers
gramming language. As long as each de- mance, and you have service level agree- on the products table to insert a row into
veloper is aware of the inputs and ex- ments that demand a certain number of the products_archive table after every
pected outputs, both developers can transactions per second or a response update or delete. You would not create a
work in parallel. This can be a way of time in a certain number of milliseconds, trigger that is fired after an insert be-
best leveraging the expertise of your de- you will want to investigate the merits of cause to query the entire history for a
velopers, if the project is large enough to using stored procedures. If you operate a product, you would retrieve the union of
Listing 1: The database schema for these examples
01 CREATE TABLE products ( 14 27 quantity MEDIUMINT NOT
NULL DEFAULT 0,
02 id MEDIUMINT NOT 15 CREATE TABLE order_headers (
NULL AUTO_INCREMENT, 28 PRIMARY KEY (id)
16 id MEDIUMINT NOT
03 name CHAR(40) NOT NULL AUTO_INCREMENT, 29 );
NULL, 17 customer_id MEDIUMINT NOT 30
04 cost DOUBLE(9,2) NULL, 31 CREATE TABLE customers (
UNSIGNED DEFAULT 0.0, 18 order_date DATETIME NOT 32 id MEDIUMINT
05 PRIMARY KEY (id) NULL, NOT NULL AUTO_INCREMENT,
06 ); 19 order_status CHAR(1) 33 name VARCHAR(70)
DEFAULT 'O',
07 NOT NULL,
20 PRIMARY KEY (id)
08 CREATE TABLE stock_quantities 34 address VARCHAR(200)
( 21 ); NOT NULL,
09 id MEDIUMINT NOT 22 35 phone VARCHAR(20)
NULL AUTO_INCREMENT, NOT NULL,
23 CREATE TABLE order_lines (
10 product_id MEDIUMINT NOT 36 email VARCHAR(40)
24 id MEDIUMINT NOT
NULL, NOT NULL,
NULL AUTO_INCREMENT,
11 quantity MEDIUMINT NOT 37 PRIMARY KEY (id)
25 order_id MEDIUMINT NOT
NULL DEFAULT 0, NULL, 38 );
12 PRIMARY KEY (id) 26 product_id MEDIUMINT NOT
13 ); NULL,
53
ISSUE 69 AUGUST 2006
W W W. L I N U X - M A G A Z I N E . C O M
3. SYSADMIN MySQL 5
the underlying will seem rather simplistic. MySQL’s pro-
view query will be cedural language is designed as a means
cached and will for providing input into SQL statements
load faster than and manipulating the results, not as a
several versions of language to compete with the likes of
the same query PHP and Java.
running from dif-
The Structure of a Stored
ferent locations.
Procedure
About the Stored procedures are written in a way
MySQL that allows them to be created by any
Procedural tool that executes SQL. Some of my list-
Language ings are displayed in MySQL Query
MySQL 5 provides Browser [6], a very useful and free tool
a procedural lan- from MySQL. They are written as SQL
Figure 1: A simple stored procedure in MySQL Query Browser.
guage you can use scripts that basically tell MySQL what
the row in the products table and the as- to create your stored procedures and the name of the stored procedure is and
sociated rows in the products_archive triggers. Instead of going for a proce- what the contents are. If the stored pro-
table. dural language based on C or Python, cedure contains any errors, MySQL will
The approach is similar when auditing the developers of MySQL created a pro- inform you when you attempt to create
is required. Instead of the approach of cedural language compliant with the the stored procedure.
having an associated archive table where ANSI SQL:2003 standard [5]. The ANSI Figure 1 shows a stored procedure that
archiving is concerned, you might have standard is used by the developers of accepts an integer value for an amount
a single audit table. For the tables you other relational database management to be added to stock. Because the default
wanted to retain an audit trail of activity systems to varying degrees, so by follow- delimiter in MySQL is a semi-colon, and
for, you might have triggers fired after ing the standard, the skillset acquired in MySQL’s procedural language uses semi-
any add, update, or delete. These trig- developing stored procedures and trig- colons to terminate each program state-
gers would insert a row into the audit gers for MySQL is transferable to other ment, we need to instruct MySQL to
table containing the nature of the action, databases such as Oracle, DB2, and Post- change the delimiter while we attempt to
the table affected, the user performing greSQL, which have similar procedural create our procedure. The usual conven-
the action, the time stamp, and any key language implementations. tion is to change the delimiter to double
data or non-key data deemed appropri- Like the programming languages you dollar signs with the DELIMITER $$
ate. The approach of using triggers in the might be familiar with, such as PHP and statement (Line 1). The next statement
database for auditing and not in your ap- Java, MySQL’s procedural language has (Line 3) instructs MySQL to drop (de-
plication code can reduce the coding the constructs you need to develop use- stroy) the existing stored procedure of
burden on your developers and encour- ful code. This includes conditional state- the same name if it exists. If it does not
age consistency in an environment ments (IF-THEN-ELSE and CASE- exist, then this statement will be ignored
where many applications access the WHEN) and iterative statements (RE- and the MySQL parser will move on.
same database. There are many good ap- PEAT-UNTIL and WHILE-DO). Line 4 instructs MySQL to create a new
proaches to auditing that can be em- The length of this article does not stored procedure with the name and pa-
ployed within your application code, so allow for an exhaustive reference of all rameters provided. All stored procedure
each case will need to be examined in MySQL procedural language features. In- logic begins with the BEGIN statement
context. stead, I will ex-
plain how MySQL
About Views stored procedures
A view is a virtual table generated from and triggers are
a stored query. The stored query is often structured and
a multi-join query taking data from provide some sim-
many tables with certain conditions at- ple examples that
tached. At a simpler, level it might be offer a flavor of
just a subset of a large table. A trivial ex- what stored proce-
ample, again using the products table, is dures, triggers and
to create a view called products_out_of_ views really are. If
stock, which joins the products table you are a sea-
with the stock_quantities table, where soned program-
the stock level is zero. mer in any mod-
Views help you cut down on writing ern language,
SQL code for commonly accessed data MySQL’s proce-
sets. Views also help efficiency because dural language Figure 2: A procedure designed to return a result set to the caller.
54 ISSUE 69 AUGUST 2006 W W W. L I N U X - M A G A Z I N E . C O M
4. SYSADMIN
MySQL 5
(Line 7). A number of declaration, se- Variables must be explicitly declared worry about and no special function or
quence, conditional, and iterative state- and assigned a type as well as an op- method calls to execute your SQL. In-
ments can follow before the stored pro- tional default value. The types you can stead, SQL statements can be run on the
cedure logic finishes with an END state- choose from are the standard SQL data fly and results read directly into vari-
ment (Line 26). Note how the END state- types for table columns. All of the data ables. UPDATE and INSERT statements
ment is followed by our temporary de- types are scalar, that is, they can only can read values directly from your vari-
limiter, the double dollars. This is be- store a single discrete value. This rules ables and parameters.
cause we have now left the stored proce- out data types such as arrays, which can In Figure 1, an UPDATE statement
dure and have returned to normal be frustrating for developers from lan- (Line 12) intermingles table names, col-
MySQL SQL parsing. At this point, we guages like PHP and Java, but there are umn names, and parameters. In the fol-
switch back to the default semi-colon workarounds, such as temporary tables lowing SELECT statement (Line 16), a
delimiter (Line 28). using a memory storage engine. Some of value is selected directly INTO an OUT
the typical data types include CHAR and parameter. As I said earlier, MySQL’s
Variables, Parameters, and VARCHAR (for characters and strings), procedural language is ultimately a
Data Types DATE, DATETIME, INT (including TI- means for inputting data to SQL and pro-
In Figure 1, I have declared one variable NYINT, SMALLINT, MEDIUMINT and cessing the results.
max_addition (Line 8) and three param- In the SELECT statement (Line 16) in
BIGINT), DECIMAL, FLOAT, DOUBLE,
eters stock_addition, product_id and and others. Large amounts of data can Figure 1, a value was selected into an
new_stock (Lines 4 to 6). The IN and be stored using other data types, such as OUT parameter. Assuming the id column
OUT keywords tell MySQL that the pa- TEXT (up to 64 kilobytes) and BLOB (bi- guarantees uniqueness, this is fine. But,
rameter can receive a value in, pass a nary large object-- in theory you can what if there were multiple values re-
value back to the caller, or both (by de- store up to 4 Terabytes in a LONGBLOB). turned by the SQL statement? You
claring a parameter to be IN OUT). Pa- should only select into a variable if you
Using SQL in Stored
rameters can be used like normal vari- are 100% certain of a single value being
Procedures
ables, but only OUT parameters should returned. This will be the case where the
have their values changed in the proce- Unlike programming languages such as discriminator (the clauses after the
dure. PHP and Java, there are no drivers to WHERE keyword) uses a unique key,
Listing 2: A stored procedure using a cursor
01 DELIMITER $$ ol.quantity) AS total_cost 44 FETCH order_summary_cur
45 INTO v_o_id
21 FROM products p
02
46 , v_c_name
22 , customers c
03 DROP PROCEDURE IF EXISTS show_
orders_processed $$ 47 , v_c_phone
23 , order_headers oh
04 CREATE PROCEDURE show_orders_ 48 , v_o_date
24 , order_lines ol
processed () 49 , v_o_total;
25 WHERE c.id = oh.customer_
05 BEGIN id 50
06 26 AND oh.id = ol.order_id 51 IF not_found THEN
07 DECLARE v_o_id MEDIUMINT; 27 AND ol.product_id = p.id 52 LEAVE order_summary_loop;
08 DECLARE v_c_name 53 END IF;
28 AND oh.order_status =
VARCHAR(70); 'P' 54
09 DECLARE v_c_phone 29 GROUP BY oh.id 55 SELECT CONCAT('Order ID: ',
VARCHAR(20);
v_o_id, ', Name: ', v_c_name,
30 , c.name
10 DECLARE v_o_date DATETIME;
56 ', Phone: ', v_
31 , c.phone
11 DECLARE v_o_total c_phone, ', Order Date: ', v_
32 , oh.order_date;
DOUBLE(9,2); o_date,
33
12 DECLARE not_found TINYINT; 57 ', Order Total:
34 DECLARE CONTINUE HANDLER FOR ', v_o_total);
13
35 NOT FOUND 58
14 /* Select all processed orders
36 SET not_found = 1;
*/ 59 UNTIL not_found
37 60 END REPEAT order_summary_loop;
15 DECLARE order_summary_cur
CURSOR FOR 38 SET not_found = 0; 61
16 SELECT oh.id 39 62 CLOSE order_summary_cur;
17 , c.name 40 OPEN order_summary_cur; 63
18 , c.phone 41 64 END $$
19 , oh.order_date 42 order_summary_loop:REPEAT 65
20 , SUM(p.cost * 43 66 DELIMITER ;
55
ISSUE 69 AUGUST 2006
W W W. L I N U X - M A G A Z I N E . C O M
5. SYSADMIN MySQL 5
cursor’s select if you were executing your SQL in
statement. To MySQL Query Browser or phpMyAdmin
fetch all of the [7].
rows returned by In the example in Listing 2, you can
our select query, simply abandon all statements between
we must use an it- the BEGIN and END other than the SQL
erative statement. query. Figure 2 shows this rather sleek
There are a num- stored procedure.
ber of ways to do Notice how I have now changed the
this, but my pre- stored procedure to receive a parameter
ferred way is the to select orders of a particular order sta-
tus. This stored procedure can now po-
REPEAT-UNTIL.
Though our RE- tentially return the result set of the query
PEAT statement to a calling program, assuming your call-
continues UNTIL ing programming language can support
a specific condi- retrieving these unbounded result sets.
tion is found to be It is possible to have multiple SQL
true (the not_ queries like in Figure 2. This may be use-
found variable, in ful for related sets of data, however, I
Figure 3: Sample PHP call to a stored procedure using mysqli.
this case), we prefer to stay clear of that approach and
such as an id column using an auto_in- have the option to LEAVE the iteration have single queries returning single re-
crement, or where you select a function before the UNTIL condition is reached. sult sets.
value into the variable, such as with To do so, we use a label to name the iter-
Example of a Stored
SUM() or MAX(). I mentioned earlier ation, order_summary_loop in this exam-
Procedure Call
that variables were scalar and could only ple. This allows us to leave the iteration
hold single values. This rules out the before using any of the fetched vari- Many of you will have been waiting for
possibility of returning a list of values di- ables, which, in the case of a fetch be- me to show some sample code for your
rectly into a variable. This is where the yond the last row, will result in an error. preferred programming language. I am
concept of cursors come to the rescue. The SELECT CONCAT statement may going to show a sample using PHP. The
look odd, but it is how we display the approach is similar for other languages
Using Cursors values returned by our cursor’s query. with MySQL driver support, such as
A cursor is a pointer into a result set re- Java, Ruby, and Python. My sample code
Returning Result Sets to
turned by a SELECT query. Though used will call the stored procedure in Figure 2.
Your Calling Code
primarily for SELECT queries that return For MySQL 5, you must have the ob-
more than one row, you can still use a If you are a hardened programmer using ject-oriented mysqli extension [8] loaded
cursor where only one row is returned. something like PHP, Java, Python or or compiled into PHP. Figure 3 shows
Even if there are no rows returned, an Ruby, you may wonder about the pur- the method calls using mysqli. Line 10
error will not be generated. However, if pose of a stored procedure like the one shows the stored procedure being called.
we try to fetch a row either from a null in Listing 2, since it only displays the re- You will notice that it does not appear to
result set or if we try and fetch beyond sult to the console or in MySQL Query be different from a normal SQL call. The
the last row in the result set, a MySQL Browser. It’s not much use if you would while statement on Line 21 loops
error will be thrown. like to manipulate the data in the result through the rows in the result set re-
Listing 2 shows my preferred way of set of that cursor.
handling cursors using REPEAT-UNTIL. It is, however,
We begin the procedure by declaring possible to return
some standard variables, including one a result set to your
called not_found. The not_found vari- calling program
able is used in conjunction with a HAN- without the cursor
DLER for the NOT FOUND condition. and handler code.
That is, when a NOT FOUND condition A plain SQL
is encountered, such as with our cursor statement can be
going beyond its bounds, the value of placed in a stored
not_found will be set to 1 or TRUE. procedure without
Our cursor order_summary_cur is declaring a cursor
nothing more than a value assigned to a and without per-
variable of that name until we actually forming a SELECT
OPEN it. Once opened, we can begin into any variables.
fetching from our cursor into variables It is written just as
in the same order as the columns in our you would write it Figure 4: The SQL to create a view.
56 ISSUE 69 AUGUST 2006 W W W. L I N U X - M A G A Z I N E . C O M
6. SYSADMIN
MySQL 5
business rules. MySQL 5 stored procedures, triggers,
Rather than hav- and views. These examples will give you
ing to write the an idea of whether these new features
update query will be useful to your software develop-
every time we ment efforts. Don’t forget that stored
order a product, procedures are all about SQL queries. If
we can create a you were writing inefficient SQL in your
trigger that is exe- program code, you will probably still be
cuted every time writing inefficient SQL queries in your
an order line is in- stored procedures.
serted. This allows The feature set is completely new to
us to have con- MySQL, but those of you who have
crete business worked with stored procedures in other
rules enforced in databases, such as Oracle, DB2, and
the database. PostgreSQL, will probably be more inter-
Listing 3 shows ested in the differences between
Figure 5: Using a view just like a regular query.
a trigger that is MySQL’s implementation and what you
turned, just like a result set returned fired after an update occurs. The NEW are used to. MySQL’s procedural lan-
from executing a normal SQL query. keyword refers to the new row values, as guage is not yet finished. Subsequent re-
they are after the update has completed. leases of MySQL 5 should improve the
Trigger Example The keyword OLD is also available and feature set considerably and address the
While stored procedures are initiated by will contain the values of the row as it areas where MySQL’s implementation
direct calls as their execution is required, was before an update or delete. For ar- falls short of its competitors.
triggers, on the other hand, are initiated chiving, for example, you might want to The documentation [9] of the new fea-
by events that cause the triggers to be insert the old row values into an archive ture set on the MySQL website is ade-
fired. The events in question are inserts, table for access to historical data. For au- quate at best, though I am being kind
updates, and deletes. diting, you might insert both old and when I write that. However, books are
Returning to the example tables in new values into an audit trail table. being published by MySQL Press and
Listing 1, we can imagine a scenario You can also have a trigger fired before other publishers that give a more de-
where customer A orders product B. One an update, insert, or delete occurs. This tailed overview of MySQL features. ■
approach to recording this in our data- can be useful where you want to modify
INFO
base is to execute a stored procedure the NEW row values, for example, for
that inserts an order header and an order validation purposes. [1] MySQL 5.0 Community Edition:
line and then updates the stock quantity http://www.mysql.com/products/data
A View Example
for the product. However, another ap- base/mysql/community_edition.html
proach is to say that any time an order In Listing 2, we had an attractive looking [2] Oracle’s PL/SQL Technology Center:
line is created, the corresponding stock piece of SQL that retrieved processed http://www.oracle.com/technology/
quantity for the product ordered will al- order summaries. For many applications, tech/pl_sql/index.html
ways be reduced by the quantity or- this may be a useful result set to have [3] Hibernate Object Relational Mapper
dered. We can consider this one of our around and re-use in several places for Java and .NET:
within your application. A view is a http://www.hibernate.org/
Listing 3: A simple after mechanism for us to store and re-use [4] ActiveRecord Object Relational
update trigger such useful queries and access them as Mapper for Ruby: http://rubyforge.
org/projects/activerecord/
if they were just a regular table. The un-
01 DELIMITER $$
derlying complexity of the query is hid- [5] A Publication on ANSI SQL:2003 by
02 CREATE TRIGGER order_lines_ Eisenberg et al: http://www.sigmod.
den from us, and we can simply select
ins_trg org/sigmod/record/issues/0403/E.
columns from this virtual table.
JimAndrew-standard.pdf
03 AFTER UPDATE ON order_lines Views cannot accept parameters. If
[6] MySQL Query Browser:
FOR EACH ROW you need your query to accept parame-
http://www.mysql.com/products/
ters, you must create a stored procedure.
04 BEGIN
tools/query-browser/
Figure 4 shows the query from Listing 3
05 UPDATE stock_quantities
[7] phpMyAdmin: http://sourceforge.net/
created in the form of a view. Figure 5
06 SET quantity = quantity projects/phpmyadmin
shows the results of running a query
- NEW.quantity [8] PHP’s mysqli extension:
using the view. Notice how it looks like
http://www.php.net/mysqli
07 WHERE product_id = NEW. a query against any regular table.
product_id; [9] MySQL’s rather sparse online docu-
Next Steps mentation for stored procedures:
08 END $$
http://dev.mysql.com/doc/refman/5.0/
In this article I have attempted to intro-
09 DELIMITER ; en/stored-procedures.html
duce you to some of the capabilities of
57
ISSUE 69 AUGUST 2006
W W W. L I N U X - M A G A Z I N E . C O M