Perl不会在while循环中执行SQL语句

时间:2017-12-14 22:26:58

标签: perl

我写了这段代码:它应该继续检查名称,直到找到一个不存在的名称,然后它应该继续。

 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语句,它们都有效。这是唯一不起作用的。

任何帮助?

2 个答案:

答案 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语句的错误方法会使您容易出现故障。