问题 如何根据变量选择架构?


考虑:

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");

这似乎没有效果:mysql回来了:

您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以便在'@REFRESHDB .Metadata`附近使用正确的语法

据我所知,我已经做好了事情 文件。然而MySQL表示不允许这样做。这是MySQL的一些限制(不允许使用变量作为标识符)或其他什么?


863
2017-09-30 15:29


起源



答案:


文件说明:

“可以从一组有限的数据类型中为用户变量分配值:整数,十进制,浮点,二进制或非二进制字符串或NULL值”

您正在尝试将变量用作对象。这不受支持。


3
2017-09-30 15:33



我没有看到如何分配给可以使用变量的变量控件。 - Billy ONeal
你用它作为一个对象,暗示着它的价值 @REFRESHDB 是一个架构对象,而不是它实际上的字符串值。 - Jeremy Holovacs
Downvoter关注评论? - Jeremy Holovacs
我正在给你和安倍晋三一个赞成这个。如果没有动态SQL(Abe为我们提供了使用DSQL的方法),使用MySQL语法无法做到这一点,这实际上是一件好事,因为它简化了安全性和性能方面的考虑。对于那些在野外散步的人来说,有DSQL。 - Christopher McGowan


答案:


文件说明:

“可以从一组有限的数据类型中为用户变量分配值:整数,十进制,浮点,二进制或非二进制字符串或NULL值”

您正在尝试将变量用作对象。这不受支持。


3
2017-09-30 15:33



我没有看到如何分配给可以使用变量的变量控件。 - Billy ONeal
你用它作为一个对象,暗示着它的价值 @REFRESHDB 是一个架构对象,而不是它实际上的字符串值。 - Jeremy Holovacs
Downvoter关注评论? - Jeremy Holovacs
我正在给你和安倍晋三一个赞成这个。如果没有动态SQL(Abe为我们提供了使用DSQL的方法),使用MySQL语法无法做到这一点,这实际上是一件好事,因为它简化了安全性和性能方面的考虑。对于那些在野外散步的人来说,有DSQL。 - Christopher McGowan


您将不得不使用prepare语句/动态SQL来执行此操作。

本文详细介绍了这两个方面:

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

尝试这个:

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;

8
2017-09-30 15:33



CREATE TABLE语句失败。 - Billy ONeal
哦,我错过了,你也必须把它放到准备好的声明中。我已经更新它以将create table放入准备好的语句中。 - Abe Miessler
通过这种更正,您所拥有的功能,但对于任何打算实现此功能的人,请注意安全性和性能注意事项。动态SQL可能有点像黑色艺术。 - Christopher McGowan


我建议你写一个存储过程:

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
2017-09-30 15:46



它在CREATE TABLE语句中失败,而不是插入。 - Billy ONeal