【问题标题】:MySQL Error codes 1064 and 2014 in stored procedures存储过程中的 MySQL 错误代码 1064 和 2014
【发布时间】:2020-06-28 00:26:37
【问题描述】:

我是 MySQL 新手,正在尝试编写一些 MySQL 存储过程,但遇到了一些我无法修复的错误。

重现错误的简单存储过程

DELIMITER //
DROP PROCEDURE IF EXISTS testing;
CREATE PROCEDURE testing(sqlQuery varchar(100))
BEGIN
PREPARE stmt FROM sqlQuery;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;

我正在应用服务器上构建动态 sql 查询,并将其作为参数发送到 MySQL 数据库服务器。

为简单起见,我们假设 sqlQuery 包含SELECT * FROM Users

当我第一次在 MySQL Workbench 中执行存储过程时,我得到:

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 'sqlQuery; EXECUTE stmt ; DEALLOCATE PREPARE stmt; END' at line 5

当我第二次执行它时,我得到:

Error Code: 2014 Commands out of sync; you can't run this command now

我找不到这些错误背后的原因。有人可以提供一些信息吗?谢谢。


MySQL:8.0.19

MySQL 工作台:8.0.19

【问题讨论】:

  • 该错误不可能来自您显示的程序。它说程序中有q;这样的行。
  • 提示 - 如果您是 MySQL 新手,请不要从 SP 开始。它们很难调试,即使你得到了正确的。它们的用处也被大大夸大了,尤其是那些不这样做的老师。
  • @Barmar 对不起,我已在帖子中将参数名称更改为更有意义的名称,但从控制台复制了错误,但未将参数名称从 q 更改为 sqlQuery
  • @danblack 即使您有多年的 MySQL 经验,也不应该使用存储过程。 :-)
  • 此外,版本控制方面经常被忽视。随着新访问尝试使用现有方法,导致 SQL 效率下降。

标签: mysql sql stored-procedures


【解决方案1】:

MYSQL 想要user variables for prepared statements:

在存储程序上下文中准备的语句不能引用存储过程或函数参数或局部变量,因为它们在程序结束时超出范围,并且如果稍后在程序之外执行该语句,它们将不可用。作为一种解决方法,请参阅用户定义的变量,这些变量也具有会话范围。

所以你需要一个中间赋值:

DROP PROCEDURE IF EXISTS testing;

DELIMITER //
CREATE PROCEDURE testing(sqlQuery varchar(100))
BEGIN
    SET @sql = sqlQuery;
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END //

DELIMITER ;

Demo on DB Fiddle

【讨论】:

    【解决方案2】:

    您不能在存储过程中使用局部变量。您必须为准备好的语句使用用户变量。

    Local variable scope and resolution

    因为局部变量仅在存储程序期间才在作用域内 执行,在准备好的语句中不允许引用它们 在存储的程序中创建。准备好的语句范围是 当前会话,而不是存储的程序,因此该语句可以是 程序结束后执行,此时变量不会 不再在范围内。

    所以,只需将参数重新分配给用户变量。

    DELIMITER //
    DROP PROCEDURE IF EXISTS testing;
    CREATE PROCEDURE testing(sqlQuery varchar(100))
    BEGIN
    SET @a = sqlQuery;
    PREPARE stmt FROM @a;
    EXECUTE stmt ;
    DEALLOCATE PREPARE stmt;
    END //
    DELIMITER ;
    

    这应该可行

    【讨论】:

      猜你喜欢
      • 2018-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 1970-01-01
      • 1970-01-01
      • 2012-08-02
      相关资源
      最近更新 更多