1

MySQL 5.2,CentOS 6.4。

当列名和表名从第一次通过时更改为不同的值时,MySQL SELECT * 在第一次通过后使用动态列和表名创建的临时表上失败。

解决方法是使用一个列别名,该别名在每次传递中保持不变。

DROP PROCEDURE IF EXISTS test1;
DELIMITER $$
CREATE PROCEDURE test1( column_name VARCHAR(20), table_name VARCHAR(20) )
BEGIN
    SET @prepared_stmt_arg = 'prepared_stmt_arg_value';

    DROP TABLE IF EXISTS tmp1;
    CREATE TEMPORARY TABLE tmp1
        SELECT 1 AS col_tmp1;

    DROP TABLE IF EXISTS tmp2;
    CREATE TEMPORARY TABLE tmp2
        SELECT 2 AS col_tmp2;

    # drop tmp table if it exists
    DROP TABLE IF EXISTS tmp_test1;

    # prepared statement
    SET @prepared_stmt = 
        CONCAT("
            CREATE TEMPORARY TABLE tmp_test1
                SELECT ? AS prepared_stmt_arg, ", column_name, " # AS constant_col_alias
                    FROM ", table_name, "
            "); # END statement

    # display prepared statement before executing it
    SELECT @prepared_stmt;

    # prepare the statement
    PREPARE ps FROM @prepared_stmt;

    # execute
    EXECUTE ps USING @prepared_stmt_arg;

    # deallocate
    DEALLOCATE PREPARE ps;

    # display
    SELECT * FROM tmp_test1;

END $$
DELIMITER ;

过程最后的 SELECT 语句失败。(您可能需要向下滚动才能看到错误消息。)

mysql> CALL test1('col_tmp1', 'tmp1');
+---------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                  |
+---------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp1 # AS constant_col_alias
                                                FROM tmp1
                                 |
+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+----------+
| prepared_stmt_arg       | col_tmp1 |
+-------------------------+----------+
| prepared_stmt_arg_value |        1 |
+-------------------------+----------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> CALL test1('col_tmp2', 'tmp2');
+---------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                  |
+---------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp2 # AS constant_col_alias
                                                FROM tmp2
                                 |
+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

ERROR 1054 (42S22): Unknown column 'dev.tmp_test1.col_tmp1' in 'field list'

但是,如果您取消注释列别名(删除之前的 # AS constant_col_alias),一切正常。(您可能需要向下滚动才能看到 Query OK。)

mysql> CALL test1('col_tmp1', 'tmp1');
+-------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp1 AS constant_col_alias
                                                FROM tmp1
                                 |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+--------------------+
| prepared_stmt_arg       | constant_col_alias |
+-------------------------+--------------------+
| prepared_stmt_arg_value |                  1 |
+-------------------------+--------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> CALL test1('col_tmp2', 'tmp2');
+-------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp2 AS constant_col_alias
                                                FROM tmp2
                                 |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+--------------------+
| prepared_stmt_arg       | constant_col_alias |
+-------------------------+--------------------+
| prepared_stmt_arg_value |                  2 |
+-------------------------+--------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
4

1 回答 1

1

好吧,它似乎是 5.6 版之前的错误或功能(如果您愿意)。

请参阅错误 #32868 存储的例程不检测元数据中的更改。

解决方法:通过执行以下操作刷新存储的例程缓存:
CREATE OR REPLACE VIEW tmpviewAS SELECT 1;

这是SQLFiddle演示 MySql 5.1.X
这是SQLFiddle演示 MySql 5.5.X

如果你注释掉CREATE OR REPLACE VIEWtmpviewAS SELECT 1你会得到你的错误。

这是SQLFiddle演示 MySql 5.6.X 表明它不再是问题


现在您至少可以使用以下选项:

  1. 不要改用SELECT *使用显式列名。
  2. 使用建议的解决方法
  3. 升级到 5.6.X
于 2013-08-25T23:54:37.883 回答