我必须使用两个参数制作一个程序:kol
和agg
。 kol
显然是列,agg
是一个聚合函数。
假设我有下表:
+---------+---------+
| X (int) | Y (int) |
+---------+---------+
| 5 | 2 |
| 4 | 4 |
+---------+---------+
我想调用('X','sum')
这个程序 - 然后它会显示SELECT SUM(x) FROM table
所以9. ('Y','avg')
显示SELECT AVG(y) FROM table
所以3。
我有一些东西,但在涉及SUM
,AVG
,MIN
和MAX
时它不起作用,它只适用于计数(适用于SUM
,AVG
,MIN
和MAX
显示0,不知道原因):
-- I skipped some lines in procedure, only this is necessary
BEGIN
IF(kol IN (select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where
TABLE_NAME='table')) THEN
-- getting every column for table above
SELECT (
CASE
WHEN agg='SUM' THEN sum(kol)
WHEN agg='COUNT' THEN count(kol)
WHEN agg='AVG' THEN avg(kol)
WHEN agg='MAX' THEN max(kol)
WHEN agg='MIN' THEN min(kol)
END) Result FROM table;
END IF;
END
答案 0 :(得分:1)
您可以使用以下解决方案:
DELIMITER //
CREATE PROCEDURE testProc (IN col VARCHAR(10), IN agg VARCHAR(10))
BEGIN
SET @select = '';
-- get the select part with the aggregation function.
-- using UPPER to allow case-insensitive input.
SELECT CASE
WHEN UPPER(agg) = 'SUM' THEN CONCAT('SUM(', col, ')')
WHEN UPPER(agg) = 'COUNT' THEN CONCAT('COUNT(', col, ')')
WHEN UPPER(agg) = 'AVG' THEN CONCAT('AVG(', col, ')')
WHEN UPPER(agg) = 'MAX' THEN CONCAT('MAX(', col, ')')
WHEN UPPER(agg) = 'MIN' THEN CONCAT('MIN(', col, ')')
END
INTO @select;
-- create and prepare the full statement.
SET @stmt = CONCAT('SELECT ', @select, ' AS Result FROM table_name');
PREPARE stmtExec FROM @stmt;
-- execute the statement.
EXECUTE stmtExec;
END//
我使用您的数据尝试了此解决方案并获得以下结果:
CALL testProc('x', 'SUM'); -- 9
CALL testProc('y', 'SUM'); -- 6
CALL testProc('x', 'COUNT'); -- 2
CALL testProc('y', 'COUNT'); -- 2
CALL testProc('x', 'AVG'); -- 4.500
CALL testProc('y', 'AVG'); -- 3.000
CALL testProc('x', 'MAX'); -- 5
CALL testProc('y', 'MAX'); -- 4
CALL testProc('x', 'MIN'); -- 4
CALL testProc('y', 'MIN'); -- 2
您不能将column参数用作聚合函数的参数。但是你可以创建一个字符串并在准备好的语句中使用它(参见上面的解决方案):
用户变量旨在提供数据值。它们不能直接在SQL语句中用作标识符或标识符的一部分,例如在需要表或数据库名称的上下文中,或作为SELECT等保留字。
这个原则的一个例外是用户变量不能用于提供标识符,就是在构造一个字符串以用作稍后执行的预准备语句时。在这种情况下,用户变量可用于提供语句的任何部分。
来源: https://dev.mysql.com/doc/refman/5.7/en/user-variables.html
在评论中提供了一些其他信息后,我将PROCEDURE
更改为以下解决方案。在那里你也得到了结果的列名和聚合函数:
DELIMITER //
CREATE PROCEDURE testProc (IN col VARCHAR(10), IN agg VARCHAR(10))
BEGIN
SET @select = '';
-- get the select part with the aggregation function.
-- using UPPER to allow case-insensitive input.
SELECT CASE
WHEN UPPER(agg) = 'SUM' THEN CONCAT('SUM(', col, ')')
WHEN UPPER(agg) = 'COUNT' THEN CONCAT('COUNT(', col, ')')
WHEN UPPER(agg) = 'AVG' THEN CONCAT('AVG(', col, ')')
WHEN UPPER(agg) = 'MAX' THEN CONCAT('MAX(', col, ')')
WHEN UPPER(agg) = 'MIN' THEN CONCAT('MIN(', col, ')')
END
INTO @select;
-- create and prepare the full statement.
SET @stmt = CONCAT('SELECT CONCAT(\'', col, '|', UPPER(agg), '|\', ', @select, ') AS Result FROM table_name');
PREPARE stmtExec FROM @stmt;
-- execute the statement.
EXECUTE stmtExec;
END//
所以我再次测试了这个解决方案,现在得到以下结果:
CALL testProc('x', 'SUM'); -- x|SUM|9
CALL testProc('y', 'SUM'); -- y|SUM|6
CALL testProc('x', 'COUNT'); -- x|COUNT|2
CALL testProc('y', 'COUNT'); -- y|COUNT|2
CALL testProc('x', 'AVG'); -- x|AVG|4.5000
CALL testProc('y', 'AVG'); -- y|AVG|3.0000
CALL testProc('x', 'MAX'); -- x|MAX|5
CALL testProc('y', 'MAX'); -- y|MAX|4
CALL testProc('x', 'MIN'); -- x|MIN|4
CALL testProc('y', 'MIN'); -- y|MIN|2