我写了这段代码:它应该继续检查名称,直到找到一个不存在的名称,然后它应该继续。
while ($repeating == 1) {
$new_name = $i . "_" . $file;
my $sql= "SELECT file_name FROM PDFdocument WHERE user_id = '$id' AND file_name = '$new_name' ";
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
//never enters here
if ($new_name ne $row[0]) {
$repeating = 0;
}
}
$i++;
}
它永远不会进入第二个while
循环,因此它会在这个重复循环中陷入困境。我不知道为什么它不起作用;之前我做了一些其他的sql语句,它们都有效。这是唯一不起作用的。
任何帮助?
答案 0 :(得分:2)
问题是如果名称不存在,您将不会获得任何行。解决方案是检查是否有任何行 - 否则文件名应该未使用。顺便说一下,让DBI转发你发送到数据库的东西。这应该有效:
while ($repeating == 1) {
$new_name = $i . "_" . $file;
# the question marks are placeholders
my $sql= "SELECT file_name FROM PDFdocument WHERE user_id = ? AND file_name = ? ";
my $sth = $dbh->prepare($sql);
# filling the placeholders while executing
$sth->execute($id, $new_name);
if(!$sth->fetch) {
# no rows found? this name must be fresh
$repeating = 0;
}
$i++;
}
编辑:正如@ikegami在评论中提到的,$sth->rows
的行为取决于驱动程序,因此在处理SELECT语句时它可能会为不同的数据库引擎返回不同的值(另请参阅the DBI docs)。要求驱动程序获取一行应该对所有驱动程序都一样。
请记住,这很容易受到竞争条件的影响,即如果两个脚本同时运行,它们可能都选择了相同的“未使用”文件名。确保你使用某种锁定机制来避免这种情况。
答案 1 :(得分:2)
当您最终找到应使用的$i
时,$sth->fetchrow_array
会返回一个空列表,因此=
会返回0
,因此不会输入循环。
解决方案1:
my $new_name;
for (my $i=1; ; ++$i) {
$new_name = $i . "_" . $file;
$dbh->selectrow_arrayref(
"SELECT 1 FROM `PDFdocument` WHERE `user_id` = ? AND `file_name` = ?",
undef,
$id, $new_name,
)
and last;
}
解决方案2:
my $i = $dbh->selectrow_array(
"
SELECT CAST(LEFT(`file_name`, LOCATE("_", `file_name`)-1) AS INT) AS `i`
FROM `PDFdocument`
WHERE `user_id` = ?
AND `file_name` LIKE ?
ORDER BY DESC `i`
LIMIT 1
",
undef,
$id, "%\\_\Q$file\E"
);
++$i;
my $new_name = $i . "_" . $file;
注意占位符的使用。如果没有攻击,那么构建SQL语句的错误方法会使您容易出现故障。