【问题标题】:Mysql stored procedure don't take table name as parameterMysql存储过程不以表名作为参数
【发布时间】:2011-09-30 09:17:56
【问题描述】:

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

让我们在 MySQL 中查看我的 proc:

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 变量作为表输入参数包含在内,则会显示错误。

表“db_test.newsinfotable”不存在

为什么这只发生在表参数上?我怎样才能从这个错误中检索或

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

【问题讨论】:

    标签: mysql stored-procedures


    【解决方案1】:

    查询的那部分不能是动态的。

    您可以考虑将其实现为在运行时动态执行的字符串

    【讨论】:

      【解决方案2】:

      SP 无法使用动态表名进行优化,因此包括 MySQL 在内的许多 DB 不允许动态指定表名。

      解决此问题的一种方法是使用动态 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,不过要小心 SQL 注入。您可能希望根据预先批准的表列表测试表名,以免表名被用户操纵为atable where (1=1) union all select username from mysql.user; '-- 或类似的东西。我会创建一个名为approvedtables 的表并在select id into approvedid from approvedtables where tablename like newsinfotable limit 1 中进行测试,如果批准不为空,则仅执行动态查询。
      • 我什至会说每个表一个 SP...那么您不仅可以在表名周围获得注入保护,而且还可以提供更好的性能,即使只是微妙的。尽管如此,我的不是为什么,我只是去做和发布,有点发火,感到受伤,做一杯冰沙让疼痛消失,过上幸福的生活,然后死在一个装满芝士蛋糕的游泳池里。
      • 你好,从你上面的例子中我写了一个商店过程。但它给出了错误:错误代码:1327 未声明的变量:第三。请看下面我的过程:如果存在则删除过程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() ,'=?;');从@sql_stam 准备s1; SET @where_param = DATE_FORMAT(date_time,'%Y-%m-%d');使用@where_param 执行s1;选择@新闻; END$$ 分隔符;
      • 亲爱的@jeff Parker:你能帮我解决这个错误吗?根据你的指示,我写了一个 SP。它执行正确,但是当我调用 SP 时出错。所以,这是我的请求对你来说,如果你请在stackoverflow.com/questions/6612530/…看到我的新问题
      • @riad 似乎有人打败了我......但如果他们的解决方案不起作用,请告诉我:)
      【解决方案3】:

      您可以将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
      

      【讨论】:

        【解决方案4】:

        虽然可能不是你想要的,但也可以考虑有条件地使用 if 并准备语句。

        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$$
        

        【讨论】:

          猜你喜欢
          • 2013-06-11
          • 1970-01-01
          • 2016-08-23
          • 1970-01-01
          • 2019-06-28
          • 2022-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多