MySQL 5 Stored Procedures, Triggers and Views - An Article by Larkin Cunningham


Published on

MySQL 5 Stored Procedures, Triggers and Views - A Feature Article by Larkin Cunningham that appeared in Linux Magazine

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

MySQL 5 Stored Procedures, Triggers and Views - An Article by Larkin Cunningham

  1. 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 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. 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. 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. 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 = oh.customer_ 05 BEGIN id 50 06 26 AND = ol.order_id 51 IF not_found THEN 07 DECLARE v_o_id MEDIUMINT; 27 AND ol.product_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 55 SELECT CONCAT('Order ID: ', VARCHAR(20); v_o_id, ', Name: ', v_c_name, 30 , 10 DECLARE v_o_date DATETIME; 56 ', Phone: ', v_ 31 , 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 39 62 CLOSE order_summary_cur; 17 , 40 OPEN order_summary_cur; 63 18 , 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. 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. 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 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 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 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- 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: 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 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 $$ 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