Py学习  »  DATABASE

如何将数据插入到MySQL中的动态表中?

Freddy Limachi Ortega • 4 年前 • 443 次点击  

我试图使用下面的存储过程在mysql的动态表中插入数据,但使用以下命令调用时出错:

CALL insert_data ('table_x', 'NULL', 'A', 'B', 'C', 'D', 'E ')

错误

Column unknown' 0 'in the list of fields.

程序

DELIMITER $$
CREATE PROCEDURE insertar_datos (name VARCHAR(25), N INT, AP 
VARCHAR(15),
AM VARCHAR(15), Nom VARCHAR(30), DNI VARCHAR(8), Direc VARCHAR(30))
BEGIN
    SET @tableName = Name;
    SET @NName= N;
    SET @APName = AP;
    SET @AMName = AM;
    SET @NomName = Nom;
    SET @DNIName = DNI;
    SET @DirecName = Direc;
    SET @q = CONCAT('
        INSERT INTO `' , @tableName, '` VALUES(
            `',@NName,'`,
            `',@APName,'`,
            `',@AMName,'`,
            `',@NomName,'`,
            `',@DNIName,'`,
            `',@DirecName,'`
        )
    ');
    PREPARE stmt FROM @q;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END $$
DELIMITER;    
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/46491
 
443 次点击  
文章 [ 1 ]  |  最新文章 4 年前
Schwern
Reply   •   1 楼
Schwern    5 年前

如果发现自己拥有多个具有相同列的表,那么可能会有一个设计不良的模式。对于一个设计良好的模式,您所要求的不是必需的。我鼓励你问一个关于如何设计你的模式来避免你的问题的另一个问题。


将未筛选的字符串连接在一起容易受到 SQL Injection attack 是的。相反,只要有可能,使用绑定参数并将值传递到。这样可以确保它们被正确地转义和引用,不会被意外或恶意地曲解。

SET @q = 'INSERT INTO `' , @tableName, '` VALUES(?,?,?,?,?,?)';
PREPARE stmt FROM @q;
EXECUTE stmt USING @NName, @APName, @AMName, @NomName, @DNIName, @DirectName

这也解决了你的其他问题,不是所有的事情都是一串。

CALL insert_data ('table_x', 'NULL', 'A', 'B', 'C', 'D', 'E ')
                              ^^^^

绑定参数将保留非字符串的类型,如整数和空值。我也会注意到 N 是一个整数,但您使用它作为通常表示字符串的名称。所以这可能是个问题。


关于那个讨厌的表名。我们不能把它作为一个绑定参数来传递。你要确保它不能跳出引号,所以必须转义。你也不希望任何人能跳转到另一个数据库,所以 . 也必须逃走。或者更好, raise an error 是的。我们不能用 quote() 因为这是针对具有不同引用规则的列值的。我们得自己写。

DELIMITER $$
drop procedure if exists check_table_name;
CREATE PROCEDURE check_table_name (
    table_name varchar(255)
)
begin
    if( locate("`", table_name) ) then
        signal sqlstate '45000'
            set message_text = 'illegal ` in table name';
    elseif( locate(".", table_name) ) then
        signal sqlstate '45000'
            set message_text = 'illegal . in table name';
    end if;
end $$
DELIMITER ;

现在我们在使用表名之前调用它。

call check_table_name(@tableName);
SET @q = concat('INSERT INTO `' , @tableName, '` VALUES(?,?,?,?,?,?)');
PREPARE stmt FROM @q;
EXECUTE stmt USING @NName, @APName, @AMName, @NomName, @DNIName, @DirecName;
DEALLOCATE PREPARE stmt;

如果是淘气,我们会出错的。

mysql> call insertar_datos("foo`haha, I broke your quoting`bar", 23, 'A', 'B', 'C', 'D', 'E ');
ERROR 1644 (45000): illegal ` in table name

但是再一次 我强烈反对这种做法 是的。任何时候,你把字符串串在一起做SQL语句时,你就有漏洞和安全缺陷的风险。我不相信 check_table_name 把所有的问题都解释清楚了。

如果必须采用这种方法,请考虑使用一组固定的允许名称。

if name in ("foo", "bar", "baz", "table_x") then
    set @tableName = name;
else
    signal sqlstate '45000'
        set message_text = 'unknown name';
end if;

我建议您考虑重新设计您的模式。