mysql - 使用准备好的语句将表名保存在存储过程内的变量中

标签 mysql stored-procedures prepared-statement

我正在尝试使用我定义的变量来分配表的名称。我的代码如下所示

DELIMITER //

CREATE PROCEDURE karawane ()
BEGIN
declare last_inserted_number VARCHAR(100) DEFAULT '0800100200';
declare last_inserted_code VARCHAR(100) DEFAULT 'Lorem Ipsum';
declare current_dataset VARCHAR(100) DEFAULT 'Lorem Ipsum';

set last_inserted_number = (select messagefrom from current_dataset where id = last_insert_id());
set last_inserted_code = (select statuscode from current_dataset where id = last_insert_id());

if(last_inserted_code = 201) then

PREPARE haus FROM 'update ? set the_status = 'online' where device_number = last_inserted_number';
set current_dataset = (select task_name from running_tasks limit 1);
EXECUTE haus USING @current_dataset;

end if;

END //

我希望在像这样的触发器中使用这个存储过程

SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE='STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
DELIMITER //
CREATE TRIGGER `le_log_trigger` AFTER INSERT ON `messagelog` FOR EACH ROW BEGIN

call karawane();

END//
DELIMITER ;

但是我的程序karawane()有这个错误

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 'online' where device_number = last_inserted_number';
set current_dataset = 

为什么会出现这个错误?

编辑我的新存储过程

DELIMITER //

CREATE PROCEDURE karawane ()
BEGIN
declare last_inserted_number VARCHAR(100) DEFAULT '0800100200';
declare last_inserted_code VARCHAR(100) DEFAULT 'Lorem Ipsum';
declare current_dataset VARCHAR(100) DEFAULT 'Lorem Ipsum';

set last_inserted_number = (select messagefrom from current_dataset where id = last_insert_id());
set last_inserted_code = (select statuscode from current_dataset where id = last_insert_id());

if(last_inserted_code = 201) then

SET @cd = (select task_name from running_tasks limit 1);
SET @sql = CONCAT('update ',@cd,' set the_status = ''online'' where device_number = ?';
PREPARE haus FROM @sql;
EXECUTE haus USING last_inserted_number;

end if;

END //

当我尝试这个时,我的新错误是

您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在 '; 附近使用的正确语法。 从 @sql 准备 haus; 使用last_inserted_number执行haus;

最佳答案

一个问题是一个简单的语法问题,字符串文字中的单引号必须“转义”为两个单引号字符。这将是语法错误:

SELECT 'It's great'

要在字符串文字中包含单引号,您需要执行以下操作:

SELECT 'It''s great'

您的过程的一个更大问题是您无法将标识符(表名称、列名称、存储程序名称等)传递为一个参数。标识符必须在 SQL 文本中指定。 (这是因为MySQL如何解析和执行语句。)

MySQL 必须解析有效的语法(关键字、匹配括号、运算符等)和语义(标识符是对表、列、存储程序等的有效引用,用户具有所需的权限等。

MySQL必须制定一个执行计划,包括访问哪些表和列、使用哪些索引、连接顺序等。

最后,MySQL将执行准备好的语句。

一旦您了解了 MySQL 如何处理查询,就会清楚为什么标识符必须是实际 SQL 文本的一部分,并且不能作为参数提供。

您只能将数据值作为准备好的语句中的参数传递。


您可以在过程中执行类似的操作,根据查询结果更改要更新的表:

SET @cd = (select task_name from running_tasks limit 1);
SET @sql = CONCAT('update ',@cd,' set the_status = ''online'' where device_number = ?');
PREPARE haus FROM @sql;
EXECUTE haus USING @last_inserted_number;
DEALLOCATE haus;

您可以动态创建包含要执行的 SQL 文本的字符串。您可以使用变量为字符串赋值,但是当该字符串传递给 PREPARE 调用时,所有标识符都是 SQL 文本的一部分。

请注意,SQL 语句可以包含的绑定(bind)占位符。我已经在更新语句的 WHERE 子句中演示了这一点。

该演示使用 MySQL 用户定义的变量(有时称为“ session ”变量),而不是过程变量。 (用户定义的变量以 @ 字符开头;过程变量是在 MySQL 存储程序中声明的变量名称,并且以 @ 字符开头。在过程中,您也许可以使用过程变量来代替用户定义的变量。

关于mysql - 使用准备好的语句将表名保存在存储过程内的变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25295489/

相关文章:

mysql - 如何在存储过程中插入 information_schema

postgresql - 错误 : date/time field value out of range in Postgresql

MYSQL - 存储过程和准备好的语句处理引号

mysql - 搜索查询 - 邮政编码、公司名称或位置

mysql - HQL 在子查询和子句中不起作用

mysql - 通过VBA在Access前端中执行带有参数的MySQL存储过程

php - 使用 MySQL 数据库的准备语句返回特定列

java - SQL 准备语句创建表

mysql - 当加载的原始数据具有许多唯一字符时,如何将 CSV 数据加载到 MySQL 数据库中

MySQL select re-ask+简化