Sie sind auf Seite 1von 13

Kevin Bedell on Internet Tech

Discussions on Ruby on Rails, Agile Development and the Boston Tech Scene. Home Contact Me MySQL Writing / Publications
Ads by Google
MySQL PL SQL Editor SQL DBA Training SQL Exam SQL Procedure

A Simple Example of a MySQL Stored Procedure that uses a cursor


Posted by Kevin on Monday, March 2nd 2009 Digg it Bookmark it Stumble it Email to friend 2 Mar (Save this to Del.icio.us!)

What is a cursor and when should you use one?


A cursor in MySQL is essentially just the result set thats returned from a query. Using a cursor allows you to iterate, or step through, the results of a query and perform certain operations on each row thats returned. Think of them like holders for any data you might process in a loop. As youll see below, the example here runs a query then loops through the results. Cursors have some drawbacks and you dont want to use them everywhere. An appropriate use for a cursor might be when you need to step through the results of a query and then perform operations on multiple tables for each row. Another candidate for a cursor is where some steps of the processing are optional and only need to be performed for certain rows. The cursor allows you to iterate through the result set and then perform the additional processing only on the rows that require it.

When should cursors be avoided?


Cursors should be avoided generally whenever you can write a SQL statement that processes all rows in a query at once and youll be surprised at how often this is. If you try, many procedures with cursors in them can be refactored

to eliminate the cursor by using a bit more complex SQL. This is an advantage usually for a couple reasons. First, by processing all rows at once instead of looping through them one at a time, its generally faster. Second, cursors can make some issues more complex to debug

MySQL Cursor Sample Code


Heres an example of how to create a MySQL stored procedure that uses a cursor. I over-commented the procedure a bit (if there is such a thing!), but I wanted the code to be relatively self-explanatory for people who just cut/paste it. The SQL required to setup the tables and data follows the example. Everything runs and is tested. It requires MySQL 5.0 or above since before that there was no support for stored procedures. First, heres the sample code. Ill follow after with some explanation.
/* * Procedure Name : usp_cursor_example * Database/Schema : foo * * Description: * An example of a MySQL stored procedure that uses a cursor * * * Tables Impacted : * foo.friend_status - read-only * DDL? - None * DML? - Only Selects * * Params: * name_in - the name of the friend to search for * * Revision History: * * Date: Id: Comment: * 2009/03/01 kbedell Original * * Copyright (c) 2009 Kevin Bedell * Can be resused under terms of the 'MIT license'. * * To test: * - Multiple records: call foo.usp_cursor_example('John'); * - One record: call foo.usp_cursor_example('Julie'); * - Zero records: call foo.usp_cursor_example('Waldo'); * */ DROP PROCEDURE IF EXISTS `foo`.`usp_cursor_example`; DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `foo`.`usp_cursor_example`( IN name_in VARCHAR(255) ) READS SQL DATA BEGIN /* All 'DECLARE' statements must come first

*/ -- Declare '_val' variables to read in each record from the cursor DECLARE name_val VARCHAR(255); DECLARE status_update_val VARCHAR(255); -- Declare variables used just for cursor and loop control DECLARE no_more_rows BOOLEAN; DECLARE loop_cntr INT DEFAULT 0; DECLARE num_rows INT DEFAULT 0; -- Declare the cursor DECLARE friends_cur CURSOR FOR SELECT name , status_update FROM foo.friend_status WHERE name = name_in; -- Declare 'handlers' for exceptions DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE; /* Now the programming logic */ -- 'open' the cursor and capture the number of rows returned -- (the 'select' gets invoked when the cursor is 'opened') OPEN friends_cur; select FOUND_ROWS() into num_rows; the_loop: LOOP FETCH INTO , friends_cur name_val status_update_val;

-- break out of the loop if -- 1) there were no records, or -- 2) we've processed them all IF no_more_rows THEN CLOSE friends_cur; LEAVE the_loop; END IF; -- the equivalent of a 'print statement' in a stored procedure -- it simply displays output for each loop select name_val, status_update_val; -- count the number of times looped SET loop_cntr = loop_cntr + 1; END LOOP the_loop; -- 'print' the output so we can see they are the same select num_rows, loop_cntr; END DELIMITER ;

Discussion and Explanation of the MySQL Cursor Example Code


The Declaration section Before any actual programming logic starts, you need to first list all declarations. This is a requirement of MySQL. Heres the declaration section:
/* All 'DECLARE' statements must come first */ -- Declare '_val' variables to read in each record from the cursor DECLARE name_val VARCHAR(255); DECLARE status_update_val VARCHAR(255); -- Declare variables used just for cursor and loop control DECLARE no_more_rows BOOLEAN; DECLARE loop_cntr INT DEFAULT 0; DECLARE num_rows INT DEFAULT 0; -- Declare the cursor DECLARE friends_cur CURSOR FOR SELECT name , status_update FROM foo.friend_status WHERE name = name_in; -- Declare 'handlers' for exceptions DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;

There are 4 sections to the declaration section: Declaration of one variable to hold the value of each column in the result of the query. Here, I recommend simply naming each variable by adding _val to the end of the actual returned column name. Also, make sure the types match! Declaration of variables that are used for counting rows and controlling looping. Generally, every stored procedure that uses a cursor can always simply have the same set. In this example we have three variables a boolean that gets set if we try to read from the cursor when no data is left, and two counters for the number of rows processed (we have two here because the example demonstrates two different methods of counting rows processed use either of them). Declaration of the actual query that will generate the result set to be held by the cursor The query is not actually invoked until later in the procedure where the cursor is opened. Also, in this example you can see that the cursor uses a variable in its where clause that is passed in as an argument to the procedure. Declaration of handlers to control execution. These are usually always the same.

This is a standard declaration that sets up processing for when the cursor contains no (or no more) rows. Opening the cursor and finding the number of rows returned The next step is to open the cursor. This is where the actual query in the cursor is run and one of the places where cursor programming can get tricky.
-- 'open' the cursor and capture the number of rows returned -- (the 'select' gets invoked when the cursor is 'opened') OPEN friends_cur; select FOUND_ROWS() into num_rows;

Notice that we select FOUND_ROWS() into our num_rows variable directly after we open the cursor. The FOUND_ROWS() information function contains the number of rows found in the last select statement run. If the query fails or errors for some reason, the open call will fail and it can fail silently. This is one of the issues with cursors you need to make sure that your queries work and are solid. You also need to make sure that they are tolerant to data changing over time. Make sure that if the underlying data in the table changes over time, your query will still work. Looping through the cursor result set There are multiple methods for looping in MySQL I use this method and recommend that you just cut/paste this code for every cursor you write. This method works and you wont have to think about it.
the_loop: LOOP FETCH INTO , friends_cur name_val status_update_val;

-- break out of the loop if -- 1) there were no records, or -- 2) we've processed them all IF no_more_rows THEN CLOSE friends_cur; LEAVE the_loop; END IF; -- the equivalent of a 'print statement' in a stored procedure -- it simply displays output for each loop select name_val, status_update_val; -- count the number of times looped SET loop_cntr = loop_cntr + 1; END LOOP the_loop;

There are a couple things to point out here. First, note that the no_more_rows variable gets set automatically when you FETCH from the cursor. For this reason you should always test for that condition immediately after you try to read a row. Note that we have a counter in the loop here as well. This is just another way to count the rows processed. Use what

works for you. Conclusion In this post, we gave some sample code that can be used/reused to create MySQL Stored Procedures containing a cursor. Best of luck with the code and feel free to post comments below if you find any problems or if you have any suggestions! Setup code for the sample MySQL Stored Procedure with a Cursor Here is the setup SQL I used to create the tables/data you need to test the stored procedure and cursor.
/* * Procedure/File Name : ex1_setup.sql * Database/Schema : foo * * Description: * Setup file to support simple cursor example * * Tables Impacted : * foo.friend_status - drop/re-create table and populate. * * Params: * None. * * Revision History: * * Date: Id: Comment: * 2009/03/01 kbedell Original * * Copyright (c) 2009 Kevin Bedell * Can be resused under terms of the 'MIT license'. * * To test: * - Run script then: select * from foo.friend_status; * */ drop table if exists foo.friend_status; CREATE TABLE IF NOT EXISTS `foo`.`friend_status` ( `id` INTEGER(10) unsigned NOT NULL auto_increment, `name` VARCHAR(255) NOT NULL, `status_update` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`) ); insert into foo.friend_status (name, status_update) values ('John', 'Woke up. Guiness for Brkfst.') , ('Fred', 'is thinking about joining the circus') , ('Erin', "Getting ready for a job interview") , ('Amy', 'at work and dreaming of kittens') , ('John', 'Watching Scooby Doo reruns. Guiness for Lunch.') , ('Amy', 'dreaming of fuzzy slippers and wedding dresses') , ('Julie', 'is hating working two jobs') , ('John', 'Out of the shower finally. Guiness for Dinner.')

, , , , , ;

('Erin', ('Amy', ('Erin', ('Amy', ('John',

"if I don't get this job, I'll be asking 'Paper or Plastic?'") 'dreaming of Meeting Mr. Right!') 'Nailed the job interview -- calling John to celebrate!') 'John called -- meeting him at the pub!') 'Heading out to meet friends for some Guiness!')

Subscribe to the post comments feeds or Leave a trackback Filed under: mysql View Comments Tags: how-to, mysql

Add New Comment


Optional: Login below.

Image

Showing 9 comments
Sort by Popular now Subscribe by email Subscribe by RSS

Nirav Raval 2 months ago

good explantions. But if u want more specific description with example of M ysql Stored Procedure, Function or Triggers you can visit, http://niravjavadeveloper.blog... Thanx... Flag
2 people liked this.

No 6 months ago

you forgot $$ after the last END ine the exemple


4 people liked this.

Nmudiraj003 2 months ago

it helps me a lot.Thanks
1 person liked this.

Solwinapp 5 months ago

Thanks Nice Article.. i got good help to learn SP with cursor


1 person liked this.

Bren 6 months ago

good article, just what i needed. Thanks!


1 person liked this.

Alma 3 weeks ago

not a long time ago post. helped me a lot.. thanks!

Jiykoth 3 months ago

Thanks for sharing this; was extremely helpful!

gUEST 4 months ago

nothing to useful

Pradeep 5 months ago

This Article is very good to practice,it works very good Thx a lot to the author

blog comments powered by DISQUS

Top Reasons I like my Mac The future of programming? To provide the means for creating innovation. Subscribe in a reader

MYOB EXO www.kilimanjaro-consulting.com.au MYOB Enterprise Solutions For Growing Businesses Free Cursors www.CursorMania.com Browse our collection of cursors for your desktop. They are so cool! SAS Data connectivity www.datadirect.com Access to nearly any data Superior Performance Free Trial Expe rt PHP Deve lopme nt www.terah.com.au Trust a local Brisbane company Industry certified PHP engineers

Click here to follow me on Twitter!

About Me
I'm an experienced Ruby/Rails Developer and Agile Technical Manager. I write Ruby/Rails code, work on systems deployments and have some good expertise in overall Technical and Management Consulting. Here's a link to my resume (PDF). Contact me at kbedell AT gmail.com.

Follow me on Twitter or view my profile on linkedin! Here's a partial list of my writing and speaking credits. Recommendations: Kevin is one of the best "agile programmers" I have come across. His work is always thorough and of high quality. His impressive communication skills and critical thinking make him a great addition to any team. - Anand Rajaram, Architect, jPeople Kevin is smart, talented, and highly motivated. He keeps up with the latest trends in technology and is always looking to learn more. I'd recommend him to anyone looking to add some technical depth to their existing team or organization. - Jeffrey Bienkowski, AVP, E-Business , Sun Life Financial I had the opportunity of working with Kevin at Viridien. Kevin has excellent work ethics, and was a pleasure to work with. His main strengths included ... technology expertise in the J2EE space, strong leadership & interpersonal skills, and reliability; he could be relied on to deliver, especially in a high pressure environment. - Chinmay Nadkarni , Software Engineer , Signature Consultants, Inc

Kevin is one of the most talented and hardest workers I know. His work is of the highest quality. He is an asset to any company. - Patt Steiner, Owner, VentureSphere and Management Consulting Specialist
Certified Consultants www.jamesandmonroe.com For certified Analysis Services, and SQL Server consultants QA, OHS & Enviro Systems www.AssuredHealthAndSafety.com.au ISO 9001: AS 4801: ISO 14001 System Purchase Instant Download Australia PHP Deve loper www.RemoteStaff.com.au/PHPdeveloper Get a Full-Time Staff For Only $1 Book an Interview, Get Started Now! Create an online store www.spiffystores.com Sell Online from just $25 a month Try Spiffy Stores for 14 days free!

Products and Services of varying usefulness:

Recent Entries Recent Comment Most Comment Securing Cloud-Based Ruby on Rails Applications: Why I like Engine Yard. JQuery-UI verus SimpleForm for Rails Forms processing How To Get Started with Ruby on Rails Where should you start? Interview with Eric S. Raymond Who Owns Unix? Interview with David Heinemeier Hansson (DHH), Creator of Ruby on Rails. Open Source Developers Are Rock Stars! BarCamp Boston 6, April 9-10, 2011 Cambridge, MA Example code for storing environment-specific configuration variables in rails How to validate an email address using regular expressions seed data versus testing data (and custom rake tasks) for Ruby on Rails

Search

Search

Categories
Uncategorized (3) twitter (2) programming (15) mac (2) lists (2) mysql (6) management (8) ruby on rails (15) leanstartup (19)

personal_insight (5) agile (11) sprint (2) scrum (3) rails (7) career (3) quora (1) code (4) interview (2) open source (3) jquery (1) cloud (1) aws-ec2 (1)

Archives
June 2011 (3) May 2011 (1) April 2011 (2) March 2011 (7) February 2011 (4) January 2011 (4) December 2010 (4) November 2010 (1) September 2010 (2) June 2010 (1) May 2010 (6) April 2010 (1)

Pages
Contact Me MySQL Writing / Publications

Links
Follow me on Twitter 21st Century Citizen My linkedin Profile My Musical Projects

Subscribe

Browse Our Tag Archives

how-to image innovation insight interview investing leanstartup list mac management metaprogamming mobileapps mysql named_scope oauth omniauth opensource picture planning programming quora rails rake revenue ruby
activerecord agile-development angel api blogs cambridge development elamf facebook funny

ruby on rails scrum software sprint startup startups strategy test_data twitter vc
My Latest Twitter Updates
(Follow Me on Twitter) I just got one of the first US Spotify accounts because I have Klout! #SpotifyPerk Find out if you're eligible: http://t.co/hYjyszS 1 day ago Should bicycles be BANNED in Boston?! Watch as this proposal is literally ripped to shreds. http://t.co/R7OdL6W 1 day ago Two weeks of vacation and my @klout score fell by 5 points. That's a good sign I was appropriately unplugged.... ;-) 1 day ago Am I the only one bored by Google+? I don't want to share content and read the content other people share. 2 days ago "Why do you keep putting your top hat on my lunch?" - http://i.imgur.com/UCMme.jpg 2 days ago More updates...

Links
21st Century Citizen - 21st Century Citizen an environmental blog I own and periodically contribute to. Follow me on Twitter - Follow me on Twitter My linkedin Profile - My linkedin Profile My Musical Projects - My Musical Projects

Recent Updated Post


Securing Cloud-Based Ruby on Rails Applications: Why I like Engine Yard. JQuery-UI verus SimpleForm for Rails Forms processing How To Get Started with Ruby on Rails -- Where should you start? Interview with Eric S. Raymond - "Who Owns Unix?" Interview with David Heinemeier Hansson (DHH), Creator of Ruby on Rails. Open Source Developers Are Rock Stars! BarCamp Boston 6, April 9-10, 2011 Cambridge, MA Example code for storing environment-specific configuration variables in rails How to validate an email address using regular expressions 'seed' data versus 'testing' data (and custom rake tasks) for Ruby on Rails 2007-2011 Kevin Bedell on Internet Tech Disclaimer: All data and information provided on this site is for informational purposes only.

Das könnte Ihnen auch gefallen