2011-09-30 12 views
11

Considere:¿Cómo selecciono un esquema basado en una variable?

SET @PREFIX='DEV_'; 

SET @REFRESHDB=CONCAT(@PREFIX,'Refresh'); 

CREATE TABLE @REFRESHDB.`Metadata` 
(
    `Key` VARCHAR(30) NOT NULL, 
    `Value` VARCHAR(30) NOT NULL, 
    PRIMARY KEY (`Key`) 
) ENGINE = InnoDB; 

INSERT INTO @REFRESDB.`Metadata` (`Key`, `Value`) VALUES ("Version", "0"); 

esto no parece ser válida: mysql se vuelva con:

Usted tiene un error en su sintaxis SQL; compruebe el manual que corresponde a su versión del servidor MySQL para el sintaxis derecho al uso cerca de '@ REFRESHDB.`Metadata`

Por lo que yo puedo decir que he hecho las cosas correctamente de acuerdo con the documentation. Sin embargo, MySQL dice que no está permitido. ¿Es esto alguna limitación de MySQL (que no permite el uso de variables como identificadores) o algo más?

Respuesta

3

estados Documentación:

variables de usuario" se puede asignar un valor de un conjunto limitado de tipos de datos: entero, decimal, punto flotante, cadena binaria o no binaria, o valor NULL "

Está intentando usar la variable como un objeto. Esto no es compatible.

+0

No veo cómo se puede asignar lo que se puede asignar a la variable donde se puede usar la variable. –

+0

Lo está usando como un objeto, lo que implica que el valor de '@ REFRESHDB' es un objeto de esquema, no el valor de cadena que realmente es. –

+1

¿A quién le importa el votante? –

8

Deberá usar prepare statement/dynamic sql para hacer esto.

Este artículo repasa ambos en excelente detalle:

http://rpbouman.blogspot.com/2005/11/mysql-5-prepared-statement-syntax-and.html

Prueba esto:

SET @PREFIX='DEV_'; 

SET @REFRESHDB=CONCAT(@PREFIX,'Refresh'); 

SET @st = CONCAT('CREATE TABLE ', @REFRESHDB,'.`Metadata` 
(
    `Key` VARCHAR(30) NOT NULL, 
    `Value` VARCHAR(30) NOT NULL, 
    PRIMARY KEY (`Key`) 
) ENGINE = InnoDB'); 

PREPARE tStmt FROM @s; 
EXECUTE tStmt; 


SET @s = CONCAT('INSERT INTO ', @PREFIX, '.`Metadata` (`Key`, `Value`) VALUES ("Version", "0")'); 

PREPARE stmt FROM @s; 
EXECUTE stmt; 
+0

La sentencia CREATE TABLE falla. –

+0

Oh, lo eché de menos, tendrás que poner eso en una declaración preparada también. Lo he actualizado para poner la tabla de creación en una declaración preparada. –

+0

Con esa corrección, lo que tiene funciona, pero para cualquiera que tenga la intención de implementarlo, tenga en cuenta las consideraciones de seguridad y rendimiento. SQL dinámico puede ser un poco de arte negro. –

0

Yo sugeriría que escribir un procedimiento almacenado:

DELIMITER $$ 
CREATE PROCEDURE (IN DBname varchar(255) 
       , IN AKey varchar(255) 
       , IN AValue varchar(255)) 
BEGIN 
    DECLARE query VARCHAR(1000); 
    -- First check the DBName against a list of allowed DBnames, 
    -- to prevent SQL-injection with dynamic tablenames. 

    DECLARE NameAllowed BOOLEAN; 
    SELECT 1 INTO NameAllowed WHERE DBName IN ('validDB1','validDB2'); 
    IF (NameAllowed = 1) THEN BEGIN 

    -- DBName is in the whitelist, it's safe to continue. 
    SET query = CONCAT('INSERT INTO ' 
         ,DBName 
         ,'.MetaData (`key`,`value`) values (?,?)); 
    -- note the use of parameter placeholders, to prevent SQL-injection. 
    PREPARE stmt FROM query; 
    EXECUTE stmt USING Akey, AValue; 
    DEALLOCATE PREPARE stmt; -- clears the query and its result from the cache. 
    END; END IF; 
END $$ 

DELIMITER ; 
+0

Está fallando en la sentencia CREATE TABLE, no en la inserción. –

Cuestiones relacionadas