2012-12-16

MySQL: Result set in a @variable

A solution of passing a result set between stored routines is frequently asked question on the official MySQL's Stored Procedures forum (see e.g. Calling PROCEDURE on SELECT output, Use resultset from sproc in select statement or in another sproc, and others).

Since MySQL does not support passing result sets in stored procedures, common practice is to use TEMPORARY TABLES when working with larger data sets.

01.CREATE PROCEDURE `lib_Explode`(sSepar VARCHAR(255), saVal TEXT)
02.body: BEGIN
03. 
04.  DROP TEMPORARY TABLE IF EXISTS lib_Explode;
05.  CREATE TEMPORARY TABLE lib_Explode(
06.    `pos` int unsigned NOT NULL PRIMARY KEY auto_increment,
07.    `val` VARCHAR(255) NOT NULL
08.  ) ENGINE=Memory COMMENT='Explode() results.';
09. 
10.  SET @saTail = saVal, @iSeparLen = LENGTH( sSepar );
11. 
12.  create_layers:
13.  WHILE @saTail != '' DO
14.    # Get the next value
15.    SET @sHead = SUBSTRING_INDEX(@saTail, sSepar, 1);
16.    SET @saTail = SUBSTRING( @saTail, LENGTH(@sHead)+1+@iSeparLen );
17.    INSERT INTO lib_Explode SET val = @sHead;
18.  END WHILE;
19. 
20.END $$

Although, this approach introduces a drawback – you have to care about table names. There are three options:

  • Keep track of the table names used. Leads to total chaos in table names.
  • Use dynamic prepared statements. Leads to awful code.
  • Use some naming conventions. Leads to many table renamings.

(I personally prefer the last option.)

The much more ellegant solution would be if a variable could hold a result set. Let's see what would be possible with such feature.

Storing a result set into a @variable

First, let's create a 3 × 2 table:

1.CREATE TABLE table1 ( a INT, b INT );
2.INSERT INTO table1 VALUES (1,2), (3,4), (5,6);
3.SELECT * FROM table1;

The table now looks like this:

a b
1 2
3 4
5 6

Currently, we can select a single value into a variable:

1.SELECT a FROM table1 INTO @var LIMIT 1;

But what much more cool would be if we could store a result set:

1.##  Create the result set and store it in a variable.
2.SELECT * FROM table1 INTO @resultset;
3.  -- or --
4.SET @resultset = (SELECT * FROM table1);

MySQL would recognize that we are assigning a result set. After executing, @resultset would be of special type RESULTSET. Then, we could pass it to a stored procedure.

Passing a result set as a parameter of a stored procedure

1.CREATE PROCEDURE StoredProcedure( rsData RESULTSET ) BEGIN
2.  SELECT a + b FROM rsData;
3.END $$
4. 
5.##  Pass the result set into a stored procedure.
6.CALL StoredProcedure( @resultset );

In the stored procedure, a RESULTSET param could act exactly as a TEMPORARY table.

Retrieving a result set from a stored procedure

1.##  Retrieving a result set from a stored procedure
2.CALL StoredProcedure() INTO @result;
3. 
4.-- or
5. 
6.SET @result = (CALL StoredProcedure());

After executing, @result would be of special type RESULTSET and contain the result of the first SELECT performed in a procedure.

Retrieving multiple result sets from a stored procedure

Multiple results from a CALL could also be fetched:

1.CREATE PROCEDURE StoredProcedure( rsData RESULTSET ) BEGIN
2.  SELECT a + b FROM rsData;
3.  SELECT a * b FROM rsData;
4.END $$
5. 
6.##  Retrieving multiple result sets from a stored procedure
7.CALL StoredProcedure() INTO @result1, @result2;

So. This is my suggestion of how to deal with result sets in stored procedures. Hopefully I will see it in MySQL some day – it would reduce the code of my procedures near to half.


0