【问题标题】:Why does this SQL PREPARE .. EXECUTE give a syntax error in MySQL 8 but not in MariaDB为什么这个 SQL PREPARE .. EXECUTE 在 MySQL 8 中给出语法错误,但在 MariaDB 中没有
【发布时间】:2021-08-30 19:17:36
【问题描述】:

是的,还有一个关于移植代码的问题!

我的 ISP 已从 MariaDB 10.4 “升级”到 MySQL 8.0,我现在必须调整很多以前工作的代码。以下存储过程在 MariaDB 中运行没有错误,但在 MySQL8 中,我在 PREPARE / EXECUTE 周围出现语法错误。实际错误是

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 
     'sql_string;
      EXECUTE do_update;
      END LOOP update_table;  -- her' at line 32

谁能推荐正确的 MySQL 语法?

(可能是 CONCAT,但看起来不错,并且在 MariaDB 中总是有效)

程序定义如下,报语法错误接近尾声。

DELIMITER $$
CREATE PROCEDURE `redact_member_id_in_all_tables`( member_id_to_replace INT, redacted_member_id INT )
    BEGIN
        DECLARE finished INT;
        DECLARE sql_string TEXT;
            DECLARE the_table_name TEXT;
    
        -- declare cursor for a data set containing all the base table names that have a column 'memberID
        -- see https://dataedo.com/kb/query/mariadb/find-tables-with-specific-column-name
        DECLARE table_cursor CURSOR FOR
                        SELECT tab.table_name
                        FROM information_schema.tables AS tab
                        INNER JOIN information_schema.columns AS col
                        ON col.table_schema = tab.table_schema
                        AND col.table_name = tab.table_name
                        AND column_name = 'member_id'
                        WHERE tab.table_type = 'BASE TABLE';    
        
        -- declare NOT FOUND handler
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
            SET finished = 0;
            
        -- open the data set containing the table name
        OPEN table_cursor;
        
        update_table: LOOP  -- 'update_table:' is a label identifying this loop
            FETCH table_cursor INTO the_table_name; -- get one table name
            IF finished = 1 THEN 
                LEAVE update_table;
            END IF;
            -- build update statment list
            SET sql_string = CONCAT('UPDATE ', the_table_name, ' SET member_id = ', redacted_member_id, ' WHERE member_id = ', member_id_to_replace)  ;
            
            PREPARE do_update FROM sql_string;
            EXECUTE do_update;
    
        END LOOP update_table;  -- here we use the label to show which loop we are ending
        CLOSE table_cursor; -- release the memory associated with the cursor
    
    END$$
    
    DELIMITER ;

【问题讨论】:

  • 我所做的方法是用实际字符串替换部分,例如填充 sql_string。在这种情况下,查看"MySQL prepare from variable" 可能会提出它们的语法。 (@sql_string)
  • 谢谢,但我还是没看出哪里不对。您提供的链接显示mysql> SET @table = 't1'; mysql> SET @s = CONCAT('SELECT * FROM ', @table); mysql> PREPARE stmt3 FROM @s; mysql> EXECUTE stmt3;,这或多或少正是我所拥有的。我定义了一个字符串变量,其中包含通过连接字符串和表列值生成的 SQL,然后执行它,就像链接一样(除了我不使用参数,但这不重要)

标签: mariadb syntax-error prepared-statement mysql-8.0


【解决方案1】:

mysql 似乎只支持来自用户变量的 PREPARE,而不支持存储过程变量。试试:

SET @sql_string = sql_string;
PREPARE do_update FROM @sql_string;

https://dev.mysql.com/doc/refman/8.0/en/prepare.html:

PREPARE stmt_name FROM preparable_stmt ... preparable_stmt 是字符串文字或用户变量

(虽然有趣的是mariadb doc 说了同样的话,甚至强调不能使用 DECLAREd 变量;让我觉得 mariadb 被增强以允许它,但文档没有改变。)

【讨论】:

  • 谢谢。做到了。这是一个非常微妙的区别,难怪我在放弃之前一直摸不着头脑,然后在这里问。
猜你喜欢
  • 2016-03-22
  • 2023-03-17
  • 2020-04-24
  • 1970-01-01
  • 2021-08-23
  • 1970-01-01
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
相关资源
最近更新 更多