为什么我的INSERT有时会因“没有这样的字段”而失败?

时间:2008-11-30 14:46:48

标签: mysql perl insert

我多年来一直在开发中使用以下代码段。现在突然间我得到一个DB错误:没有这样的字段警告

$process = "process";
$create = $connection->query
(
    "INSERT INTO summery (process) VALUES($process)"
);
if (DB::isError($create)) die($create->getMessage($create));

但如果我使用数字

则没关系
$process = "12345";
$create = $connection->query
(
    "INSERT INTO summery (process) VALUES($process)"
);
if (DB::isError($create)) die($create->getMessage($create));

或将值直接写入表达式

$create = $connection->query
(
    "INSERT INTO summery (process) VALUES('process')"
);
if (DB::isError($create)) die($create->getMessage($create));

我真的很困惑......有什么建议吗?

2 个答案:

答案 0 :(得分:7)

使用准备好的查询和参数占位符总是更好。在Perl DBI中就像这样:

my $process=1234;
my $ins_process = $dbh->prepare("INSERT INTO summary (process) values(?)");
$ins_process->execute($process);

为获得最佳性能,请在打开数据库连接后立即准备所有常用查询。许多数据库引擎会在会话期间将它们存储在服务器上,就像小型临时存储过程一样。

它也非常有利于安全。将值写入插入字符串本身意味着必须在每个SQL语句中编写正确的转义码。使用准备和执行样式意味着只有一个位置(执行)需要知道转义,如果甚至需要转义。

答案 1 :(得分:0)

同样Zan Lynx对占位符所说的话。但是你可能仍然想知道你的代码失败的原因。

您似乎忘记了之前为您工作多年的代码中的重要细节:引号。

这个(测试过的)代码工作正常:

my $thing = 'abcde';
my $sth = $dbh->prepare("INSERT INTO table1 (id,field1)
                              VALUES (3,'$thing')");
$sth->execute;

但是下一个代码(在VALUES字段中缺少引号就像你的第一个例子那样)会产生你报告的错误,因为VALUES(3,$ thing)解析为VALUES(3,abcde)导致你的SQL服务器看起来对于一个名为abcde的字段,该字段没有字段。

my $thing = 'abcde';
my $sth = $dbh->prepare("INSERT INTO table1 (id,field1)
                              VALUES (3,$thing)");
$sth->execute;

所有这些都假定您的第一个示例不是您描述时失败的代码的直接引用,因此不是您的意图。它解析为:

"INSERT INTO summery (process) VALUES(process)"

,如上所述,导致您的SQL服务器将VALUES中的项目设置为另一个字段名称。如上所述,这实际上在没有抱怨的情况下在MySQL上运行,并且将填充名为'process'的字段为NULL,因为当MySQL在创建新记录时查找值时,该字段称为'process'。

我确实使用这种风格来快速丢弃涉及已知安全数据的黑客攻击(例如程序本身提供的值)。但是对于任何涉及来自程序外部或可能包含[0-9a-zA-Z]以外的数据的内容,它将使您免于使用占位符。