An Introduction to Stored Procedures in MySQL 5

An Introduction to Stored Procedures in MySQL 5

Tutorial Details
  • Topic: MySQL 5+
  • Difficulty: Moderate
  • Estimated Completion Time: 15 minutes

MySQL 5 introduced a plethora of new features – stored procedures being one of the most significant. In this tutorial, we will focus on what they are, and how they can make your life easier.


Introduction

“ A stored routine is a set of SQL statements that can be stored in the server.”

A stored procedure is a method to encapsulate repetitive tasks. They allow for variable declarations, flow control and other useful programming techniques.

The “academic” position on this is quite clear and supports the extensive use of stored procedures. On the other hand, when you consider the opinions of those who work with them day in, day out, you’ll notice that reactions vary from complete, unwavering support to utter hate. Keep these in mind.

Pros

  • Share logic with other applications. Stored procedures encapsulate functionality; this ensures that data access and manipulation are coherent between different applications.
  • Isolate users from data tables. This gives you the ability to grant access to the stored procedures that manipulate the data but not directly to the tables.
  • Provide a security mechanism. Considering the prior item, if you can only access the data using the stored procedures defined, no one else can execute a DELETE SQL statement and erase your data.
  • To improve performance because it reduces network traffic. With a stored procedure, multiple calls can be melded into one.

Cons

  • Increased load on the database server — most of the work is done on the server side, and less on the client side.
  • There’s a decent learning curve. You’ll need to learn the syntax of MySQL statements in order to write stored procedures.
  • You are repeating the logic of your application in two different places: your server code and the stored procedures code, making things a bit more difficult to maintain.
  • Migrating to a different database management system (DB2, SQL Server, etc) may potentially be more difficult.

The tool that I am working with in this tutorial, MySQL Query Browser, is pretty standard for database interactions. The MySQL command line tool is another excellent choice. I make note of this because the popular phpMyAdmin doesn’t support stored procedure execution.

Additionally, I’ll be using very rudimentary table structures, strictly to ease the explanation. I’m showing off stored procedures, and they’re complex enough without worrying about big tables.


Step 1 – Picking a Delimiter

The delimiter is the character or string of characters that you’ll use to tell the mySQL client that you’ve finished typing in an SQL statement. For ages, the delimiter has always been a semicolon. That, however, causes problems, because, in a stored procedure, one can have many statements, and each must end with a semicolon. In this tutorial I will use “//”


Step 2 – How to Work with a Stored Procedure

Creating a Stored Procedure

DELIMITER //

CREATE PROCEDURE `p2` ()
LANGUAGE SQL
DETERMINISTIC
SQL SECURITY DEFINER
COMMENT 'A procedure'
BEGIN
    SELECT 'Hello World !';
END//

The first part of the statement creates the procedure. The next clauses defines the optional characteristics of the procedure. Then you have the name and finally the body or routine code.

Stored procedure names are case insensitive, and you cannot create procedures with the same name. Inside a procedure body, you can’t put database-manipulation statements.

The four characteristics of a procedure are:

  • Language : For portability purposes; the default value is SQL.
  • Deterministic : If the procedure always returns the same results, given the same input. This is for replication and logging purposes. The default value is NOT DETERMINISTIC.
  • SQL Security : At call time, check privileges of the user. INVOKER is the user who calls the procedure. DEFINER is the creator of the procedure. The default value is DEFINER.
  • Comment : For documentation purposes; the default value is ""

Calling a Stored Procedure

To call a procedure, you only need to enter the word CALL, followed by the name of the procedure, and then the parentheses, including all the parameters between them (variables or values). Parentheses are compulsory.

CALL stored_procedure_name (param1, param2, ....)

CALL procedure1(10 , 'string parameter' , @parameter_var);

Modify a Stored Procedure

MySQL provides an ALTER PROCEDURE statement to modify a routine, but only allows for the ability to change certain characteristics. If you need to alter the body or the parameters, you must drop and recreate the procedure.

Delete a Stored Procedure

DROP PROCEDURE IF EXISTS p2;

This is a simple command. The IF EXISTS clause prevents an error in case the procedure does not exist.


Step 3 – Parameters

Let’s examine how you can define parameters within a stored procedure.

  • CREATE PROCEDURE proc1 () : Parameter list is empty
  • CREATE PROCEDURE proc1 (IN varname DATA-TYPE) : One input parameter. The word IN is optional because parameters are IN (input) by default.
  • CREATE PROCEDURE proc1 (OUT varname DATA-TYPE) : One output parameter.
  • CREATE PROCEDURE proc1 (INOUT varname DATA-TYPE) : One parameter which is both input and output.

Of course, you can define multiple parameters defined with different types.

IN example

   DELIMITER //

CREATE PROCEDURE `proc_IN` (IN var1 INT)
BEGIN
    SELECT var1 + 2 AS result;
END//

OUT example

DELIMITER //

CREATE PROCEDURE `proc_OUT` (OUT var1 VARCHAR(100))
BEGIN
    SET var1 = 'This is a test';
END //

INOUT example

DELIMITER //

CREATE PROCEDURE `proc_INOUT` (OUT var1 INT)
BEGIN
    SET var1 = var1 * 2;
END //

Step 4 – Variables

The following step will teach you how to define variables, and store values inside a procedure. You must declare them explicitly at the start of the BEGIN/END block, along with their data types. Once you’ve declared a variable, you can use it anywhere that you could use a session variable, or literal, or column name.

Declare a variable using the following syntax:

DECLARE varname DATA-TYPE DEFAULT defaultvalue; 

Let’s declare a few variables:

DECLARE a, b INT DEFAULT 5;

DECLARE str VARCHAR(50);

DECLARE today TIMESTAMP DEFAULT CURRENT_DATE;

DECLARE v1, v2, v3 TINYINT;

Working with variables

Once the variables have been declared, you can assign them values using the SET or SELECT command:

DELIMITER //

CREATE PROCEDURE `var_proc` (IN paramstr VARCHAR(20))
BEGIN
    DECLARE a, b INT DEFAULT 5;
    DECLARE str VARCHAR(50);
    DECLARE today TIMESTAMP DEFAULT CURRENT_DATE;
    DECLARE v1, v2, v3 TINYINT;    

    INSERT INTO table1 VALUES (a);
    SET str = 'I am a string';
    SELECT CONCAT(str,paramstr), today FROM table2 WHERE b >=5; 
END //

Step 5 – Flow Control Structures

MySQL supports the IF, CASE, ITERATE, LEAVE LOOP, WHILE and REPEAT constructs for flow control within stored programs. We’re going to review how to use IF, CASE and WHILE specifically, since they happen to be the most commonly used statements in routines.

IF statement

With the IF statement, we can handle tasks which involves conditions:

DELIMITER //

CREATE PROCEDURE `proc_IF` (IN param1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = param1 + 1;
    
    IF variable1 = 0 THEN
        SELECT variable1;
    END IF;

    IF param1 = 0 THEN
        SELECT 'Parameter value = 0';
    ELSE
        SELECT 'Parameter value <> 0';
    END IF;
END //

CASE statement

The CASE statement is another way to check conditions and take the appropriate path. It’s an excellent way to replace multiple IF statements. The statement can be written in two different ways, providing great flexibility to handle multiple conditions.

DELIMITER //

CREATE PROCEDURE `proc_CASE` (IN param1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = param1 + 1;
    
    CASE variable1
        WHEN 0 THEN
            INSERT INTO table1 VALUES (param1);
        WHEN 1 THEN
            INSERT INTO table1 VALUES (variable1); 
        ELSE
            INSERT INTO table1 VALUES (99);
    END CASE;

END //

or:

DELIMITER //

CREATE PROCEDURE `proc_CASE` (IN param1 INT)
BEGIN
    DECLARE variable1 INT;
    SET variable1 = param1 + 1;
    
    CASE 
        WHEN variable1 = 0 THEN
            INSERT INTO table1 VALUES (param1);
        WHEN variable1 = 1 THEN
            INSERT INTO table1 VALUES (variable1); 
        ELSE
            INSERT INTO table1 VALUES (99);
    END CASE;

END //

WHILE statement

There are technically three standard loops: WHILE loops, LOOP loops, and REPEAT loops. You also have the option of creating a loop using the “Darth Vader” of programming techniques: the GOTO statement. Check out this example of a loop in action:

DELIMITER //

CREATE PROCEDURE `proc_WHILE` (IN param1 INT)
BEGIN
    DECLARE variable1, variable2 INT;
    SET variable1 = 0;
    
    WHILE variable1 < param1 DO
        INSERT INTO table1 VALUES (param1);
        SELECT COUNT(*) INTO variable2 FROM table1;
        SET variable1 = variable1 + 1;
    END WHILE;
END //

Step 6 - Cursors

Cursor is used to iterate through a set of rows returned by a query and process each row.

MySQL supports cursor in stored procedures. Here's a summary of the essential syntax to create and use a cursor.

DECLARE cursor-name CURSOR FOR SELECT ...;       /*Declare and populate the cursor with a SELECT statement */
DECLARE  CONTINUE HANDLER FOR NOT FOUND          /*Specify what to do when no more records found*/
OPEN cursor-name;                                /*Open cursor for use*/
FETCH cursor-name INTO variable [, variable];    /*Assign variables with the current column values*/
CLOSE cursor-name;                               /*Close cursor after use*/

In this example, we'll perform some simple operations using a cursor:

DELIMITER //

CREATE PROCEDURE `proc_CURSOR` (OUT param1 INT)
BEGIN
    DECLARE a, b, c INT;
    DECLARE cur1 CURSOR FOR SELECT col1 FROM table1;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET b = 1;
    OPEN cur1;

    SET b = 0;
    SET c = 0;
   
    WHILE b = 0 DO
        FETCH cur1 INTO a;
        IF b = 0 THEN
            SET c = c + a;
	END IF;  
    END WHILE;

    CLOSE cur1;
    SET param1 = c;

END //

Cursor has three important properties that you need to be familiar with in order to avoid unexpected results:

  • Asensitive : Once open, the cursor will not reflect changes in its source tables. In fact, MySQL does not guarantee the cursor will be updated, so you can't rely on it.
  • Read Only : Cursors are not updatable.
  • Not Scrollable : Cursors can be traversed only in one direction, forward, and you can't skip records from fetching.

Conclusion

In this lesson, we covered the fundamentals of stored procedures and some specific properties pertaining to them. Of course, you should continue your studies in areas like security, SQL statements, and performance before you can master MySQL routines.

You have to evaluate the advantages that stored procedures can potentially bring to your applications, and then make a reasonable implementation that fits your requirements. I generally use procedures; their benefits in terms of security, code maintenance and software design make them worthy of use, in my opinion. Additionally, remember that procedures in MySQL are still a work in progress. You should fully expect improvements, in terms of functionality and performance in the future. Please don't hesitate to comment and share your ideas and opinions.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://webdesignertutorials.com web designer tutorials

    And that’s what I call an advanced technique. Thanks, I’ll study it later, just scanned-through for now.

  • Ryan Lund

    Well I had stopped coming on here as often due to the quality/complexity of the articles dropping slightly. This however, i was impressed with. Great way to show people how to use a too-often-forgot technique. Thank you.

  • Sahan

    Gold!

  • http://denweb.ru DenWeb

    Useful information for me! Thank you!

  • http://www.it-iss.com Ronan Cashell

    Just for your information MySQL Query Browser is end of life and has been superseded with MySQL Workbench.

  • http://blog.piotrnalepa.pl menu rozwijane

    thx for sharing with article. I think it is important part of being MySQL server administrator to know how to work with procedures.

  • Jarek

    this could be very useful, for example in returning breadcrumb for pages stored in 1 table, where each record has column value of the parent page. How do you think, is this be more efficient than looping single queries?

    • Federico Leven
      Author

      It’s always more efficient return from MySQL only the required records from the tables, leaving all the data processing to the database server, if possible, than return the entire table to PHP and looping the recordset to get the same result.

  • http://www.carlosja.com CarlosJa

    I really don’t see the value of having a store procedure method. We use it here at work and I found it to be more of a headache than to really help with tasks at hand.

    Considering you’re putting more load on the database server; calling the sql statement twice and it just doesn’t really seem practical.

  • http://www.modernooze.com sam – dorset web design

    Thanks chap i needed a re-cap on this

  • http://twitter.com/jholyhead James

    I’m glad MySQL has introduced stored procedures. I always thought it terribly unfair that the MySQL community didn’t have to deal with the recurring nightmare that I like to call ‘Managing stored procs across software versions’. Enjoy, suckers!

  • kankaro

    It’s like Oracle… they’ve got packages…

  • http://rahulprasad.com Rahul Prasad

    How do we return a cursor from procedure?

    • Federico Leven
      Author

      Hi Rahul… you cannot return a cursor from a SP in MySQL. But of course you can return a SELECT to the client.

  • Hirvine

    Wow, great tutorial. That sums pretty much. Though I have still two questions:

    How do you list all registered procedures?
    How do you view a registered procedure?

  • http://connectinginsites.com wanderingDeveloper

    thank you so much for this tutorial :) its just what we need thanks :)

  • Jørgen Thulstrup

    @Hirvine
    You can list stored procedures with:
    select * from information_schema.routines;

  • http://b3ha.blogspot.com/ b3ha

    Nice article, pros and crons are okey but i miss a bit the availabilities, what kind of situations you can use store procedures… (eg for business codes)

    [a tiny bug at inout example:

    CREATE PROCEDURE `proc_INOUT` (OUT var1 INT)

    the type of the parameter its only an out]

    • Chad LaFarge

      b3ha,

      You would use a Stored Procedure where your data needs are more complex than a simple SELECT can accommodate. If your result-set must be shaped by a good deal of business logic, use a SP. If you must manipulate a great deal of data one record-a-time-time and use the resulting data as a complete result-set, use a SP.

      In short, the more complex your data selection and manipulation requirements are before you have a clean recordset, the more likely you should be using a Stored Procedure.

      Additionally, a Stored Procedure should accept variable input and handle it much more safely that inline SQL.

      Hope this is helpful.

  • Kopeka Simposya

    It is about time. Stored Procedures have been around in Microsoft SQL server for a while and they are pretty handy when it comes to data encapsulation. Excited!!!!

  • Hemant

    Great Article buddy!

    Keep it up!

  • http://1sprint.com/ Calle Hunefalk

    You write that there’s a load increase on the server – care to elaborate on that? Why would you want to increase the load on the server – I thought stored procedures ultimately could decrease the load on the server by retrieving the data in a format you want, without having to run as much PHP to parse the data and minimize the number of database calls?

    What are your thoughts?

    • Kyle

      I second Calle’s question.

      Also, in your Pros/Cons section you say

      “Increased load on the database server — most of the work is done on the server side, and less on the client side”

      By client side are you referring to the web server? That would make sense because the app code (PHP, Ruby, etc.) would have to perform the logic that the SPs would have performed.

      • KEITH

        See my answer to Calle.

        Please note that when the author refers to “client”, it is indeed the client application which may be written in MANY different languages, not just PHP.
        Consider that connections can be from applications written in C, C++, C#, VB, DELPHI, TCL, PERL, etc. Also note that these applications may be executed from an END-USER’S PC, NOT ON ANOTHER SERVER.
        So, depending on the situation, moving some of the load from the end-user’s app to the database server may improve responsiveness of the CLIENT application.
        Furthermore, as stated by one of the PROs, a change in business logic would only require an update to some stored procedures….located centrally on the database server….not in the hundreds of end-users apps that would have to be re-compiled, re-package, and re-deployed….a big PLUS for stored procedures.

        Hope that helps.

    • KEITH

      Stored procedures increase the load on the DATABASE SERVER. Not all deployments are on the same server; SEPARATE web and database servers are deployed in the real world. Furthermore, the “increase” in load on the DATABASE server may be negligible.

      Small Shop/Low Traffic Web:
      If you are running both on the same server, and issuing multiple queries where PHP presents the raw data, there MAY be an improvement in performance, as only one connection is made, and the stored procedure (MYSQL) does the heavy lifting. In reality, you are only shifting resources from APACHE/PHP to MYSQL.

      Enterprise/Heavy Traffic Web:
      If you have thousands of connections that use complex stored procedures, that may be too much for MYSQL (depending on the nature of the stored procedure….looping, nested loops are expensive operations). Iterations (looping) may be better suited for PHP. Depending on the situation, separate servers may help by off setting the load from the webserver to the database server.

      Careful design consideration and experience certainly help here.

  • http://www.keithbluhm.com Keith

    Yes, MySQL 5 did indeed introduce a plethora of new features… nearly 8 years ago! At first glance I was under the impression this was a re-visited article from 2003. :\

  • http://itcutives.com Jatin

    Nice introduction to Stored Procedures.

    Stored Procedures have been part of MySQL since v5.0, and have got long way enough.

    Before using Stored Procedures in your application or in live environment, please read the following article at MySQL Performance Blog

    http://www.mysqlperformanceblog.com/2007/06/12/mysql-stored-procedures-problems-and-use-practices/

  • http://itcutives.com Jatin

    I forgot to mention one thing though, there is a pdf about stored procedures from MySQL too.

    http://dev.mysql.com/tech-resources/articles/mysql-storedprocedures.pdf

  • Elliott

    Nice, should do one for Oracle too !

  • http://mrkdevelopment.com.au Matt

    Stored procedures have been around for ages.

    On thing to think about is when to use a stored procedure.

    In many cases a view would be better for just selecting data.

    Stored procedures are better at doing large updates and creating calculated indexes for fast retrieval at a later date.

    The main improvement in performance for MySQL for most web uses is just making sure you utilize indexes correctly.

  • Cassy

    This was soo complicated.

  • terry

    >”You are repeating the logic of your application in two different places: your server code and the stored procedures code, making things a bit more difficult to maintain.”

    I thought this statement was inaccurate. There is no reason at all to duplicate logic. It can be handled either once in the application or once in the stored procedure. Duplicating logic in all cases is a design deficiency not a limitation of stored procedures.

    • Federico Leven
      Author

      Yes, you are right, there was an error , you are not repeating but “splitting” or putting in different layers the app logic, so if you are working with the app code you have to jump from MySQL SP code to, let’s say, you PHP or Ruby code.

  • http://www.permanaj.net Permana Jayanta

    Great Article, Just like what I currently needed. Maybe next time there should be article about comparison about stored procedure in every database (MySQL, PostgreSQL, SQL Server, Oracle, etc)

  • http://www.benedikt-wolters.de MightyUhu

    So where are stored procedures actually stored and available? Are they available on the whole MySQL Server or just a selected Database?

    • Chad LaFarge

      Stored Procedures are written in the context of a database, and generally address specific tables in that database. I’m not I can come up with very many uses for SPs not specific to a known database.

  • http://www.cipro-websitedesign.co.za cipro

    Thanks for the very detailed post. I am still new to mysql but this new knowledge will become useful to me soon. cipro

  • Mr. B

    in my opinion, one that should be included on the article were the limitation when using a SP.
    such as, limitation on doing recursive… etc..
    it would a gold mine if some one could point us the list of what SP can and cant do.

  • http://www.monixer.com Juidan Ho

    MySQL still has to improve alot more.

    Nicely done article. save me time on google :)

  • mark

    why insert into is not working in my routine? is this a bug?

  • http://www.poraddarky.cz Dárky

    Please, does anybody know how to do this?

    SELECT nazev INTO jmeno FROM smanager.krestnijmeno ORDER BY RAND() LIMIT 1;
    SELECT nazev INTO prijmeni FROM smanager.prijmeni ORDER BY RAND() LIMIT 1;
    SET jmenoPrijmeni = jmeno + SPACE(1) + prijmeni;

    The third row doesn´t work properly and I can´t find a function to connect two strings into one string variable.

    • KEITH

      concatenate…..concat for short:

      SELECT CONCAT(jmeno,’ ‘,prijmeni) into jmenoPrijmeni;

      Notice the space in single quotes.

      You may need to use ‘global’ variables; in other words append @ to your variables:
      SELECT CONCAT(@jmeno,’ ‘,@prijmeni) into @jmenoPrijmeni;

      Be sure to declare your variables that way, with the @ symbol.
      Hope that helps.

  • anish sahare

    RESPECTED SIR

    PLEASE SHOW THE EXAMPLE WHERE ONE PROCEDURE CALL INSIDE ANOTHER PROCEDURE IN MY SQL .

    THANKS
    ANISH SAHARE

  • Vali

    Can i pass a Table Variable as ‘paramter’ to a Stored Procedure in My Sql..

  • Vali

    How to pass An array or Table to a Procedure In MYSQL
    as like in MSSQL(Table Value Parameter)

  • Luke

    Thanks for the article. However, I think you need to expand on calling a stored procedure with parameters. I had to do this to get the examples to work:

    call proc_OUT(@var1); SELECT @var1;

    And this is not at all clear from this:

    CALL stored_procedure_name (param1, param2, ….)

    CALL procedure1(10 , ‘string parameter’ , @parameter_var);

    Its not clear when and why you would use an @ before the varname.

  • Luke

    The INOUT example has the variable incorrectly declared. It should read:

    DELIMITER ;;
    CREATE DEFINER=`root`@`%` PROCEDURE `proc_INOUT`(INOUT var1 INT)
    BEGIN
    SET var1 = var1 * 2;
    END;;
    DELIMITER ;

  • namita jain

    great tutorial

  • Jim

    I am a veteran of MS SQL Server and use sprocs (ahem, stored procedures or routines) religiously. I just bumped back into MySQL development and love that it uses sprocs as well.

    Of all the many benefits of using sprocs, three stand out for me.

    1. The sproc (at least in SQL Server) is precompiled at the server once it is run the first time (and subsequently when the sproc is altered, etc.). This allows the SQL server to determine the most efficient way to return the requested data to get the best performance. This greatly reduces load on the business and data layers of your architecture, ie, the business layer need only call the procedure and the data layer handles what the data layer was designed best to handle, data manipulation and retrieval.

    2. As stated before, if there are multiple pages, datasets, applications, etc., relying on the same information, using a sproc makes updating the data layer transparent to the using applications. I can pretty much completely redesign the data layer and as long as the sproc takes in the same parameters and outputs the same results, how the information is processed and returned is controlled in one place, not across hundreds of pages.

    3. Just as important, if not more so than the first tow, is that the sproc, in itself, prevents a majority of SQL injections because the input is strongly typed. If someone enters a string in an input and it contains anything from the infamous “;select * from whereever” to the most clever of tries, the sproc treats it as a string and nothing gets executed. Only if the developer uses and eval statement would that get executed, which is except under the most special of circumstances a big taboo in sproc development in the first place.

    I’ve tested the third against sprocs I’m developing and it works as intended, normal SQL injections do not work when tagged into a parameter for the sproc. You can’t enter a line of text into anything but a string type input, and any string input is treated as a string and is not executed.

    My question then is about performance. Does MySQL precompile the sproc when it is first run? If so, at what point does MySQL see the performance hit? Ok, retrieving simple datatables using “SELECT * FROM someTbl WHERE id = 1″, that’s pretty straight forward and probably doesn’t deem a sproc necessary but when it gets a bit more complex when does MySQL start to falter?

    Thanks for any insight anyone can provide, appreciate it!

  • Elly mbilinyi

    Excellence tutorial

  • Andrea

    I can not run WWHERE on strings.
    Help me!!!!

    CREATE DEFINER=`root`@`localhost` PROCEDURE `new_routine`(nome varchar(20))
    BEGIN
    SELECT * FROM `new_schema`.`utenti` where Nome=nome;
    END
    .

  • Ravindu

    It’s very useful and easy to learn thanks……….

  • Joe

    To anyone who can help

    Can I get a tutorial that will biuld my knowledge in sproc on what I have learn in tutorial?

  • CB Singh

    Good tutorilal

  • http://www.curriculum-generator.com CV

    Is it possible to CALL a procedure from another procedure?

  • Muhammad

    Thanks alot

  • fdass

    Worst tutorial ever

  • Kevin

    This is great. Thanks!

  • Cjmetacrawler

    DBMS 2 CLASSMATES!!!! hahahaha