为什么这个 SQL PREPARE .. EXECUTE 在 MySQL 8 中给出语法错误但在 MariaDB 中没有

Why does this SQL PREPARE .. EXECUTE give a syntax error in MySQL 8 but not in MariaDB

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

我的 ISP 有 'upgraded' 从 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 ;

看来 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 is either a string literal or a user variable

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