【问题标题】:Getting error while running stored procedure with Dyanamic Query使用 Dynamic Query 运行存储过程时出错
【发布时间】:2013-07-05 06:39:06
【问题描述】:

我正在调用下面的存储过程,其中表名是根据当前日期生成的:

    DELIMITER $$
USE `test`$$
DROP PROCEDURE IF EXISTS `sp_pickalertstatus`$$
CREATE PROCEDURE `sp_pickalertstatus`()
BEGIN
    DECLARE msgID  BIGINT (10);
    DECLARE tbl VARCHAR(100);
    SET msgID=(SELECT alertID FROM tbl_intofone_alert_transaction WHERE 
    deliverystatus LIKE '22%' LIMIT 1); 
    IF(msgID IS NOT NULL)THEN
        SET tbl=(SELECT CONCAT('history.tbl_',DATE_FORMAT(NOW(),"%y%m%d")));
        INSERT INTO tbl (MEMBERID,SOURCE,MOBILE,SMPPID,PRIORITY,SMSID
        ,SMSCONTENTTYPE,MESSAGE,REQUESTDATETIME,DR_GROUPID,dr_service_type,
        dr_celleb_msg_id,dr_submit_date,dr_done_date,dr_stat,dr_err,dr_smppid)
        SELECT memberid,SenderID,MSISDN,SMPPID,'1',alertID,'TXT',Message,
        updatetime,'0','PIN','0',DATE_FORMAT(InTime,'ymdHis'),
        DATE_FORMAT(updatetime,'ymdHis'),'DELIVRD',
        '000','03' FROM tbl_intofone_alert_transaction WHERE alertID=msgID;         
    END IF; 
    END$$
DELIMITER ;

我收到错误“错误代码:1146 表'test.tbl'不存在”。我在这里做错了什么?

建议使用 Prepared 语句执行此操作后,我更改了上面的代码:

DELIMITER $$

USE `test`$$

DROP PROCEDURE IF EXISTS `sp_pickalertstatus22`$$

CREATE PROCEDURE `sp_pickalertstatus22`()
BEGIN
    DECLARE msgID  BIGINT (10);
    DECLARE tbl VARCHAR(100);
    SET msgID=(SELECT alertID FROM tbl_intofone_alert_transaction WHERE deliverystatus LIKE '22%' LIMIT 1); 
    IF(msgID IS NOT NULL)THEN
        SET tbl=(SELECT CONCAT('history.tbl_',DATE_FORMAT(NOW(),"%y%m%d")));
        SET @sl=CONCAT('INSERT INTO ?',' (MEMBERID,SOURCE,MOBILE,SMPPID,PRIORITY,SMSID,SMSCONTENTTYPE,MESSAGE,REQUESTDATETIME,
        DR_GROUPID,dr_service_type,dr_celleb_msg_id,dr_submit_date,dr_done_date,dr_stat,dr_err,dr_smppid)
            SELECT memberid,SenderID,MSISDN,SMPPID,?,alertID,?,Message,updatetime,?,?,?,DATE_FORMAT(InTime,?),
            DATE_FORMAT(updatetime,?),?,?,? FROM tbl_intofone_alert_transaction WHERE alertID=?');
        PREPARE stmt FROM @sl;
        SET @tbl=tbl;
        SET @pr='06';
        SET @txt='TXT';
        SET @grp='0';
        SET @srtyp='PIN';
        SET @clmsg='0';
        SET @intm='%y%m%d%H%i%s';
        SET @outm='%y%m%d%H%i%s';
        SET @drst='DELIVRD';
        SET @drerr='000';
        SET @drsmp='03';
        SET @msg=msgID;

        EXECUTE stmt USING @tbl,@pr,@txt,@grp,@srtyp,@clmsg,@intm,@outm,@drst,@drerr,@drsmp,@msg;       
    END IF; 
    END$$
DELIMITER ;

但它仍然无法正常工作?并得到一个错误

  Error Code : 1064
    You have an error in your SQL syntax; check the manual that
 corresponds to your MySQL server version for the right syntax 
to use near '? MEMBERID,SOURCE,MOBILE,SMPPID,PRIORITY,SMSID,
SMSCONTENTTYPE,MESSAGE,REQUESTDA' at line 1 

使用查询字符串执行准备语句时:

    EXECUTE stmt USING '06','TXT','0','PIN','0','%y%m%d%H%i%s'
,'%y%m%d%H%i%s','DELIVRD','000','03';

出现错误:

Error Code : 1064
You have an error in your SQL syntax; check the manual that 
corresponds to your MySQL server version for the right syntax to 
use near ''06','TXT','0','PIN','0','%y%m%d%H%i%s','%y%m%d%H%i%s','DELIVRD',
'000','03';' at line 25

【问题讨论】:

  • 尝试使用准备好的语句,CONCAT 准备的字符串中的tbl 值
  • 如果不使用PREPARE 和字符串,则不是动态查询。
  • @EliasVanOotegem 你能告诉我那个语法
  • 我已经更新了我的答案。 IMO 的问题是您尝试使用占位符 (?) 作为表名。我不认为这是可能的
  • @EliasVanOotegem 好的,但现在我想在没有“?”的情况下做同样的事情对于表名'tbl',但在执行语句命令中出错..查看最新编辑..

标签: mysql stored-procedures prepared-statement


【解决方案1】:

鉴于您的更新:不要对 tbl 名称使用占位符,像我一样在查询字符串中 CONCAT 它,以避免? ( 附近的语法错误。注意字段名称前的??它不会被 @tbl 取代。
同时松开@ 标志。您正在创建会话变量(在整个会话期间保留在内存中),这仅在需要时才有用。在存储过程中,它们是无关紧要的。过程返回后,它使用的变量可以而且应该被 GC'ed。

使用准备好的语句:

SET tbl=(SELECT CONCAT('history.tbl_',DATE_FORMAT(NOW(),"%y%m%d"))); -- set tbl as you normally would
PREPARE stmt FROM
CONCAT('INSERT INTO ', tbl, -- tbl is concatenated here
       ' (MEMBERID,SOURCE,MOBILE,SMPPID,PRIORITY,SMSID
        ,SMSCONTENTTYPE,MESSAGE,REQUESTDATETIME,DR_GROUPID,dr_service_type,
        dr_celleb_msg_id,dr_submit_date,dr_done_date,dr_stat,dr_err,dr_smppid)
        SELECT memberid,SenderID,MSISDN,SMPPID,?,alertID,?,Message,
        updatetime,?,?,?,DATE_FORMAT(InTime,?),
        DATE_FORMAT(updatetime,?),?,
        ?,?
        FROM tbl_intofone_alert_transaction WHERE alertID=msgID;');

EXECUTE stmt USING '1', 'TXT', '0', 'PIN', '0', 'ymdHis', 'ymdHis', 'DELIVRD','000', '03';

类似的东西应该可以解决问题,More info here

解决这个问题的另一种方法,仍然使用准备好的语句,可能是删除占位符:

CONCAT('INSERT INTO ', tbl,
       ' (MEMBERID,SOURCE,MOBILE,SMPPID,PRIORITY,SMSID
           ,SMSCONTENTTYPE,MESSAGE,REQUESTDATETIME,DR_GROUPID,dr_service_type,
          dr_celleb_msg_id,dr_submit_date,dr_done_date,dr_stat,dr_err,dr_smppid)
          SELECT memberid,SenderID,MSISDN,SMPPID,\'1\',alertID,\'TXT\',Message,
          updatetime,\'0\',\'PIN\',\'0\',DATE_FORMAT(InTime,\'ymdHis\'),
         DATE_FORMAT(updatetime,\'ymdHis\'),\'DELIVRD\',
        \'000\',\'03\' FROM tbl_intofone_alert_transaction WHERE alertID=msgID');

只需转义引号,或使用双引号分隔连接字符串。
不确定DATE_FORMAT 格式,不过……不应该是'%Y%d%m' 吗?

【讨论】:

  • 我怎样才能为“tbl”提供价值?
  • @Ekansh:我已经添加了您的代码、您如何设置 tbl 变量,并添加了注释,显示您将 tbl 值插入到查询中的位置
  • @Ekansh:我这样做了,也许确实使用了变量(仅在名称前没有@),或者只是将它们按原样连接到查询中。准备好的语句不需要包含占位符,它只是一种动态构建查询的方法
猜你喜欢
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 2018-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
相关资源
最近更新 更多