简体   繁体   English

MySQL SELECT *在第一次通过PREPARE使用动态列和表名创建的临时表上失败

[英]MySQL SELECT * fails on temporary table created by PREPARE using dynamic column and table names after first pass

MySQL 5.2, CentOS 6.4. MySQL 5.2,CentOS 6.4。

MySQL SELECT * fails on temporary table created by PREPARE using dynamic column and table names after first pass, when column name and table name are changed to different values from the first pass. 当列名和表名更改为与第一次遍历不同的值时,MySQL SELECT *在由PREPARE使用动态列名和表名创建的临时表上失败。

The work-around is to use a column alias that remains the same from pass to pass. 解决方法是使用一个列别名,并且每次传递都保持相同。

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 ;

The SELECT statement at the very end of the procedure fails. 该过程最后的SELECT语句失败。 (You may need to scroll down to see the error message.) (您可能需要向下滚动以查看错误消息。)

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'

However, if you uncomment the column alias (remove the # just before AS constant_col_alias ), all works well. 但是,如果取消注释列别名的注释(删除AS constant_col_alias之前的#),则一切正常。 (You may need to scroll down to see 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)

Well it seems to be a bug or a feature (if you want) up to version 5.6. 嗯,这似乎是5.6版之前的错误或功能(如果需要)。

See Bug #32868 Stored routines do not detect changes in meta-data. 请参见Bug#32868。存储的例程无法检测元数据中的更改。

Workaround: flush the stored routine cache by doing this: 解决方法:通过执行以下操作刷新存储的例程缓存:
CREATE OR REPLACE VIEW tmpview AS SELECT 1; 创建或替换视图tmpview作为选择1;

Here is SQLFiddle demo MySql 5.1.X 这是SQLFiddle演示MySql 5.1.X
Here is SQLFiddle demo MySql 5.5.X 这是SQLFiddle演示MySql 5.5.X

If you comment out CREATE OR REPLACE VIEW tmpview AS SELECT 1 you'll get your error. 如果您注释掉CREATE OR REPLACE VIEW tmpview AS SELECT 1您将得到您的错误。

Here is SQLFiddle demo MySql 5.6.X shows that it's no longer a problem 这是SQLFiddle演示MySql 5.6.X,它不再是问题


Now you have at least these options to go with: 现在至少可以使用以下选项:

  1. don't use SELECT * use explicit column names instead. 不要使用SELECT *改用显式列名。
  2. use proposed workaround 使用建议的解决方法
  3. upgrade to 5.6.X 升级到5.6.X

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM