我的代码中出现了一个奇怪的错误,似乎只有在我尝试使用占位符和引号标识符进行查询时才会出现错误。我编写了以下子程序来检查条目是否存在,如果密钥存在则返回密钥或null
如果它不存在:
sub check_exists {
my $table=$_[0]; #table
my $col=$_[1];
my $check=$_[2]; #query for item
#check if value exists
my $sql=sprintf(qq(SELECT COUNT(1) FROM %s WHERE ?=?),
$dbh->quote_identifier($table));
my $sth = $dbh->prepare($sql);
$sth->execute($col,$check);
my $result=$sth->fetch()->[0];
$sth->finish();
#if value exists find the row and return the primary key
if ($result){
my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?),
$dbh->quote_identifier=$col,
$dbh->quote_identifier=$table);
my $sth2=$dbh->prepare($sql);
$sth2->execute($col,$check);
return ($sth2->fetch()->[0]); #return key
}
else {
return 0; #else value does not exist and return null
}
}
我甚至尝试过:
my $result=$dbh->selectrow_array(sprintf(qq(SELECT COUNT(1) FROM %s WHERE ?=?),$dbh->quote_identifier($table)),undef, $col, $check);
不幸的是,它总是返回零。如果我不使用占位符,它似乎有效。
my $test=$dbh->selectrow_array(qq(SELECT COUNT(1) FROM ORF1 WHERE idORF1=?),undef,$orf1_crc32)
有人可以解释一下我做错了什么吗?
答案 0 :(得分:1)
我认为您可以从简化代码并使其执行子程序名称所说的(即检查记录的存在性)中受益。您的第二个查询执行不必要的查找以获取您已知的值,因为您首先将其传递给子例程。
为什么不做一个简单的count(*)
,它在今天的每个流行数据库中进行了优化?零/假值返回值表示记录不存在,非零/真值返回值表示记录不存在。简单。
sub check_exists {
my ($table, $col, $val) = @_;
my $sql = sprintf(
q{select count(*) from %s where %s = ?},
$dbh->quote_identifier($table),
$dbh->quote_identifier($col)
);
return $dbh->selectrow_array($sql, undef, $val);
}
if (check_exists('foo', 'bar', 42)) {
# do something ...
}
答案 1 :(得分:1)
不要对表名或列名使用占位符或变量。
相反,使用if语句在完整的SQL查询之间进行选择。
例如:
if($option eq 'name'){
$sql = 'SELECT name FROM users WHERE id = ?';
} elsif {$option eq 'id'){
$sql = 'SELECT age from users WHERE name = ?';
} else {
// STUFF
}
这将生成更多代码行,但您的代码将更具可读性。
答案 2 :(得分:0)
如果您正确复制了代码。
my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?),
$dbh->quote_identifier=$col,
$dbh->quote_identifier=$table);
看起来很有趣。我打赌你打算说
my $sql = sprintf(qq(SELECT %s FROM %s WHERE ?=?),
$dbh->quote_identifier($col),
$dbh->quote_identifier($table));