MySQL Input Parameters Add Flexibility to Crosstab Stored Procedures | Database Journal

MySQL Input Parameters Add Flexibility to Crosstab Stored Procedures

Apr 7, 2010
5 minute read

When generating a result set where the query contains an unknown number of column and/or row values we can use a combination of Prepared Statements, which allows us to tailor the output based on the number of data values. We can also add input parameters to a procedure to assign the field names, aliases, and even the aggregate function!

In the previous article of the MySQL crosstab series, entitled MySQL Prepared Statements to Generate Crosstab SQL, we worked on generating the result set where the query contains an unknown number of column and/or row values. Our solution was based on a combination of Prepared Statements, as well as the concat() and group_concat() functions. This approach allowed us to tailor the output based on the number of data values, so that we could free ourselves from having to anticipate changes down the road. In today’s installment, we are going to take things one step further by adding input parameters to our proc, so that we can assign the field names, aliases, and even the aggregate function!

Recap of the Crosstab Stored Procedure

Let’s quickly revisit the stored proc that we created to dynamically generate the SQL code and result set. Inside the procedure, we generated the SQL for the query and saved it to a variable using the SELECT INTO syntax. A Prepared Statement was then utilized to execute the generated code:

CREATE PROCEDURE `p_case_counts_per_region_by_month`() 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
BEGIN  
  SELECT concat(
    "SELECT CASE WHEN Month_Num IS NULL", "n", 
    "            THEN 'TOTAL'", "n", 
    "            ELSE Month", "n", 
    "       END        AS 'Month',", "n",
    group_concat( DISTINCT concat("       REGION_", REGION_CODE, 
                                  "  AS 'REGION ", REGION_CODE, "',", "n"
                           )
                  order by REGION_CODE
                  separator '' 
                ),
    "       TOTAL", "n",
    "FROM  (	SELECT	MONTH(CREATION_DATE)ttttttttAS Month_Num,", "n",
    "ttCONVERT(MONTHNAME(CREATION_DATE) USING latin1)tttttttttAS 'Month',", "n",  
    group_concat( 
        DISTINCT concat("ttttCOUNT(CASE WHEN REGION_CODE ='", REGION_CODE, 
                        "' THEN FEE_NUMBER ELSE NULL END) AS 'REGION_", 
                        REGION_CODE, "',", "n"
                 )
        order by REGION_CODE
        separator '' 
    ),
    "      	COUNT(*)tttttttttttttAS 'TOTAL'", "n",
    "		FROM  TA_CASES", "n",
    "		WHERE YEAR(CREATION_DATE)=", YEAR(CREATION_DATE), "n",
    "		GROUP BY Month_Num WITH ROLLUP) AS CA;"
  ) statement
  into @case_counts_per_region_by_month
  FROM TA_CASES
  WHERE YEAR(CREATION_DATE)=1998;

  prepare case_counts_per_region_by_month   
  from @case_counts_per_region_by_month;    
  execute case_counts_per_region_by_month;   
  deallocate prepare case_counts_per_region_by_month; 
END
Advertisement

Running the proc confirmed that it produced the desired results:

mysql> call p_case_counts_per_region_by_month;
MonthREGION 01REGION 02REGION 03REGION 04REGION 05TOTAL
April133376247171
May17552091143425
June8632211127420
July131042406123486
August181212749111533
September25160239288514
October9882952127521
November2862922120502
December11282326155522
TOTAL10683820783110414094

Defining the Input Parameters

All of our input parameters will be of type VARCHAR so that they can accommodate strings of variable length. For the sake of simplicity, we’ll assign all of our parameters a size of sixty four, which happens to be the maximum field name length in MySQL, as the following chart affirms:

IdentifierMaximum Length (characters)
Database64
Table64
Column64
Index64
Constraint64
Stored Function or Procedure64
Trigger64
View64
Alias256
Compound Statement Label16

The AggregateFunction Input Parameter

The AggregateFunction parameter is an especially interesting one in that it will allow us to apply different kinds of calculations on our data. MySQL supports ten such functions:

NameDescription
AVG()Return the average value of the argument
BIT_AND()Return bitwise and
BIT_OR()Return bitwise or
BIT_XOR()(v4.1.1)Return bitwise xor
COUNT(DISTINCT)Return the count of a number of different values
COUNT()Return a count of the number of rows returned
GROUP_CONCAT()(v4.1)Return a concatenated string
MAX()Return the maximum value
MIN()Return the minimum value
STD()Return the population standard deviation

Here is what the modified proc looks like with the input parameter. The new code is highlighted in Red:

CREATE PROCEDURE `p_case_counts_per_region_by_month` (IN AggregateFunction VARCHAR(64)) 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
BEGIN  
  SELECT concat(
    "SELECT CASE WHEN Month_Num IS NULL", "n", 
    "            THEN 'TOTAL'", "n", 
    "            ELSE Month", "n", 
    "       END        AS 'Month',", "n",
    group_concat( DISTINCT concat("       REGION_", REGION_CODE, 
                                  "  AS 'REGION ", REGION_CODE, "',", "n"
                           )
                  order by REGION_CODE
                  separator '' 
                ),
    "       TOTAL", "n",
    "FROM  (	SELECT	MONTH(CREATION_DATE)ttttttttAS Month_Num,", "n",
    "ttCONVERT(MONTHNAME(CREATION_DATE) USING latin1)tttttttttAS 'Month',", "n",  
    group_concat( 
        DISTINCT concat("tttt", AggregateFunction, "(CASE WHEN REGION_CODE ='", REGION_CODE, 
                        "' THEN FEE_NUMBER ELSE NULL END) AS 'REGION_", 
                        REGION_CODE, "',", "n"
                 )
        order by REGION_CODE
        separator '' 
    ),
    "      	", AggregateFunction, "(FEE_NUMBER)tttttttttttttAS 'TOTAL'", "n",
    "		FROM  TA_CASES", "n",
    "		WHERE YEAR(CREATION_DATE)=", YEAR(CREATION_DATE), "n",
    "		GROUP BY Month_Num WITH ROLLUP) AS CA;"
  ) statement
  into @case_counts_per_region_by_month
  FROM TA_CASES
  WHERE YEAR(CREATION_DATE)=1998;

  prepare case_counts_per_region_by_month   
  from @case_counts_per_region_by_month;    
  execute case_counts_per_region_by_month;   
  deallocate prepare case_counts_per_region_by_month; 
END
Advertisement

We can now easily manipulate the data using different aggregate functions, such as SUM():

mysql> call p_case_counts_per_region_by_month("SUM");
MonthREGION 01REGION 02REGION 03REGION 04REGION 05TOTAL
April811413638443727211745384298
May58692523910745622849511188303
June2901284119951020642998174026
July49495126190859149838913187480
August689155694122490294938642226666
September73427311810617344230324217399
October273630602140146114448313222941
November10723562512115054446920205311
December6905049389500171058051200444
TOTAL4056436408192165694423711251706868

…the STDDEV() function, which calculates the standard deviation:

mysql> call p_case_counts_per_region_by_month("STDDEV");
MonthREGION 01REGION 02REGION 03REGION 04REGION 05TOTAL
April137.7672765257.2432256326.3496693132.5175.1580777284.01053
May128.1031429278.5697022324.18687160159.5317314277.68481
June168.0364079242.0570553289.19890690134.5805142248.15875
July128.7976258280.643283227.240314237.06600719189.0798114236.2054
August131.3816535269.194428287.5951348238.28088149.3653913259.11602
September78.33299177264.1167589263.443922815159.1064992247.41223
October83.39064696187.6058641291.504115221208.0032344260.70436
November154213.7065439252.65184580216.7769207237.74581
December0228.2511625254.857840229.06888371208.4755833234.31828
TOTAL160.2388869252.5301334280.7877818157.2860091183.110026252.83464

…or the MAX() function, to tell us which case had the largest FEE_NUMBER:

mysql> call p_case_counts_per_region_by_month("MAX");
MonthREGION 01REGION 02REGION 03TOTAL
April691-1663-10524999-5135-56238999-3742-984677999-5135-56238
May594-1504-47250999-5135-56379999-3742-981285999-5135-56379
June690-1697-9864999-5135-56654999-3742-981607999-5135-56654
July594-1504-47295Z98-5139-36502064999-3742-981983Z98-5139-36502064
August594-1504-47308999-5135-57282999-3742-982322999-5135-57282
September477-1129-36952777Z98-5139-36993245999-3742-982652Z98-5139-36993245
October463-1697-10149999-5135-57882999-3742-982999999-5135-57882
November690-1504-473606999-5135-58093999-3742-983152999-5135-58093
December690-1697-10161999-5135-58323999-3742-983722999-5135-58323
TOTAL691-1663-10524Z98-5139-36993245999-3742-984677Z98-5139-36993245

Obviously, it would be beneficial to be able to apply the functions to other fields, so let’s add parameters for them as well.

Robert Gravelle

Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Database Journal Logo

DatabaseJournal.com publishes relevant, up-to-date and pragmatic articles on the use of database hardware and management tools and serves as a forum for professional knowledge about proprietary, open source and cloud-based databases--foundational technology for all IT systems. We publish insightful articles about new products, best practices and trends; readers help each other out on various database questions and problems. Database management systems (DBMS) and database security processes are also key areas of focus at DatabaseJournal.com.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.