2013-08-25 6 views
1

MySQL 5.2, CentOS 6.4.MySQL SELECT * не работает во временной таблице, созданной PREPARE, с использованием динамических имен столбцов и таблиц после первого прохода

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' 

Однако, если вы раскомментировать псевдоним столбца (удалить # непосредственно перед 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) 
+0

ли вы на самом деле имел в виду, чтобы иметь столбец с именем '?' Или вы имели в виду, чтобы это было заполнитель? – peterm

+0

Просто placeholder. Я только ставил его там, чтобы проиллюстрировать, что само подготовленное утверждение, похоже, функционирует должным образом. Я удалю его, поскольку это не относится к проблеме. – Michael

ответ

1

Ну это, кажется, ошибка или функцию (если вы хотите) до версии 5.6.

См Bug #32868 Stored routines do not detect changes in meta-data.

Обход: промывать хранимую рутинную кэш, делая это:
CREATE OR REPLACE VIEW 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
+0

Большое вам спасибо за помощь в этом - работает как чемпион! – Michael

+0

@Michael. Добро пожаловать. Я рад, что смог помочь :) – peterm