2011-07-07 19 views
4

我写过一个存储过程。除了将表格名称作为输入参数外,它工作正常。Mysql存储过程不把表名作为参数

让看到我PROC在MySQL:

DELIMITER $$ 
USE `db_test`$$ 

DROP PROCEDURE IF EXISTS test_proc$$ 

CREATE DEFINER=`root`@`localhost` 
PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100)) 
BEGIN     
    SELECT COUNT(*) FROM newsInfoTable WHERE newsServiceName=serviceName;   
END$$ 

DELIMITER ; 

存储过程调用参数:

USE db_test; 
CALL test_proc('abc','tbl_test_news'); 

下面的服务名称参数是工作的罚款。但是,如果我将newsInfoTable变量作为表输入参数包含,则会显示一个错误。

Table 'db_test.newsinfotable' doesn't exist

为什么只发生表参数?我如何从这个错误检索或

我如何将表名作为参数传递给存储过程?

回答

8

的SP动态执行的字符串

不能动态表名进行优化,那么多的DB时,MySQL在内,不允许动态指定表名。

解决此问题的一个方法是使用动态SQL。

CREATE DEFINER=`root`@`localhost` PROCEDURE `test_proc`(IN serviceName VARCHAR(10),IN newsInfoTable VARCHAR(100)) 
BEGIN     
    SET @sql = CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=?;'); 
    PREPARE s1 from @sql; 
    SET @paramA = serviceName; 
    EXECUTE s1 USING @paramA; 
END$$ 
+1

+1,不过要注意SQL注入。您可能希望根据预先批准的表列表来测试表名,以免表中的表名被用户操作为'atable where(1 = 1)union all从mysql.user中选择用户名; ' - '或者类似的东西。我将创建一个名为'approvedtables'的表,并将类似'select id'的测试放入批准的表中,其中像newsinfotable limit 1这样的表名只在被批准时不执行动态查询。 – Johan

+0

我甚至可以说每个桌子上有一个SP ......那么你不仅可以在表名称周围注入保护,而且即使只是巧妙地表现出更好的性能。尽管如此,我的原因并不在于为什么,我只是做和发布,发烧,感到受伤,做出冰沙让痛苦消失,过上幸福的生活,然后死在充满芝士蛋糕的游泳池里。 –

+0

你好,从你上面的例子我写了一个商店proc.But它给错误:错误代码:1327未声明的变量:Third.Please看到我的proc下面:DROP PROCEDURE,如果存在'test_proc' $$ CREATE DEFINER ='root' @ localhost' PROCEDURE'test_proc'(IN newsInfoTable VARCHAR(100)) BEGIN SET @sql_stam = CONCAT('SELECT news INTO',@news,'FROM',newsInfoTable,'WHERE',CURDATE(),'=? ;'); 准备s1来自@sql_stam; SET @where_param = DATE_FORMAT(date_time,'%Y-%m-%d'); EXECUTE s1 USING @where_param; SELECT @news; END $$ DELIMITER; – riad

-1

该查询的一部分不能是动态的。你可以考虑实施如在运行时

6

可以使用EXECUTE IMMEDIATE的“少即是多”的解决方案(对我来说,更少的代码=好)

CREATE PROCEDURE test_proc(IN serviceName VARCHAR(10), IN newsInfoTable VARCHAR(100)) 
BEGIN     
    EXECUTE IMMEDIATE CONCAT('SELECT COUNT(*) FROM ',newsInfoTable,' WHERE newsServiceName=''', serviceName, ''''); 
END 
+0

该死的这是一个很好的答案!谢谢。 –

-1

虽然可能不是你想要的东西,或者,可以考虑有条件地使用如果和准备声明。

DELIMITER $$ 
CREATE PROCEDURE select_count(IN table_name VARCHAR(20)) 
BEGIN 
    IF table_name = 'xxx' THEN 
    SELECT * FROM xxx; 
    ELSEIF table_name = 'yyy' THEN 
    ... 
    ENDIF 
END$$