在第一次传递后,使用动态列和表名称,PRE SELECT创建的临时表上的MySQL SELECT *失败

时间:2013-08-25 21:42:11

标签: mysql sql temp-tables prepare

MySQL 5.2,CentOS 6.4。

MySQL SELECT *在第一次传递后使用动态列和表名称由PREPARE创建的临时表失败,此时列名和表名从第一次传递更改为不同的值。

解决方法是使用从传递到传递保持相同的列别名。

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'

但是,如果取消注释列别名(删除#{1}}之前的#),一切正常。 (您可能需要向下滚动才能看到查询确定。)

AS constant_col_alias

1 个答案:

答案 0 :(得分:1)

好吧它似乎是一个bug或一个功能(如果你想要的话)直到​​5.6版。

请参阅Bug #32868 Stored routines do not detect changes in meta-data.

  

解决方法:通过执行以下操作来刷新存储的例程缓存:
  创建或替换视图tmpview AS SELECT 1;

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

如果你发表评论CREATE OR REPLACE VIEW tmpview AS SELECT 1,你就会收到错误。

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

<小时/> 现在你至少有这些选项:

  1. 请勿使用SELECT *使用显式列名。
  2. 使用建议的解决方法
  3. 升级到5.6.X