【问题标题】:Execute DBI query with a concatonated String使用连接字符串执行 DBI 查询
【发布时间】:2011-05-07 06:21:12
【问题描述】:

免责声明 -- Perl 非常新 --

我需要将连接的会话字符串传递给准备好的查询,如下所示

my $uniqueSessions="SELECT DISTINCT  SESSION
                    FROM   $table";

my $queryUniques = $connect->prepare($uniqueSessions);
$queryUniques->execute();
$queryUniques->bind_columns(\$session);

my $query="SELECT   session, action
           FROM     $table
           WHERE    session
           IN       (?)
           ORDER BY session, id";

my $queryPrep = $connect->prepare($query);

while($queryUniques->fetch()) {
    if($counter == 1) {
        $sessionString = "'" . $session . "'";
    } else {
        $sessionString = $sessionString . ", '" . $session . "'";
    }

    $counter++;
    if(($counter % 5) == 0) {
        $counter = 1;
        $queryPrep->execute($sessionString);
        my @test = $queryPrep->fetchall_arrayref();
    }
} 

但这并没有返回任何内容,我已经在我的数据库客户端中尝试了确切的查询并且它有效,有什么想法吗?

编辑:抱歉似乎删减了太多我已经编辑了代码以确保所有信息都存在;

返回的字符串是用单引号和逗号括起来的会话。

【问题讨论】:

    标签: perl string concatenation dbi


    【解决方案1】:

    只需问自己两个问题:

    1) 在调用execute() 之前$sessionString 的值是多少?

    2) execute 方法的返回值是多少?
    试试:

    $queryPrep->execute($sessionString) or die $queryPrep->errstr;
    

    【讨论】:

      【解决方案2】:

      $session 是从哪里来的?? 首先,我建议把

      use strict;
      

      在你的 perl 程序中,这样你就可以在它们发生之前发现许多简单的错误。

      看起来问题的症结在于您尝试构建用逗号分隔的单引号字符串。在这种情况下,我会使用一个数组来存储您需要的值,然后在您发出查询之前将它们加入。例如:

      my @sessions = ();
      
      # perhaps you meant this?
      while(my $session = $queryUniques->fetch()) {
          push @sessions, $session
      
          if((scalar @sessions) % 5 == 0) {
              my $sessionString = join ",", map { "'$_'" } @sessions;
              @sessions = ();
              $queryPrep->execute($sessionString);
              my @test = $queryPrep->fetchall_arrayref();
          }
      } 
      

      【讨论】:

      • 不要这样做,这不是Bobby Tables 安全的(如果它有效,甚至,这看起来不太可能)。看看this link,来自 Chip/Sinan 的回答。
      • 是的,我会以不同的方式接近目标 - 也许您可以详细说明自己的答案。
      【解决方案3】:

      正如其他人提到的:

      use strict;
      use warnings;
      

      此外,每次进行 DBI 调用时,都应该这样做:

      if ($sth->err()) {
        die "ERROR: " . $sth->errstr() . "\n";
      }
      

      即使在获取之后。这将捕获您可能遇到的许多问题。

      我稍微简化了你的程序:

      use strict;
      use warnings;
      
      use DBI;
      
      my $connect = DBI->connect("$connectString", "$user", "$id");
      
      if (not $connect) {
      die qq(connection error\n);
      }
      
      my $table = "session";
      my $uniqueSessions = "SELECT DISTINCT  SESSION
              FROM   $table";
      
      print qq(\$uniqueSessions = "$uniqueSessions"\n);
      
      my $queryUniques = $connect->prepare($uniqueSessions);
      if ($queryUniques->err()) {
      die "ERROR: " . $queryUniques->errstr() . "\n";
      }
      $queryUniques->execute();
      if ($queryUniques->err()) {
      die "ERROR: " . $queryUniques->errstr() . "\n";
      }
      
      my $session;
      $queryUniques->bind_columns(\$session);
      
      my $counter = 1;
      my $sessionString;
      while(my $hashref = $queryUniques->fetch()) {
      print "Fetching Row\n";
      if($counter == 1) {
          $sessionString = "'" . $session . "'";
      } else {
          $sessionString = $sessionString . ", '" . $session . "'";
      } 
      $counter++;
      }
      if ($queryUniques->err()) {
      print "ERROR = " . $queryUniques->errstr . "\n";
      }
      
      print "$sessionString\n";
      

      我基本上取出了第二个查询并在这里和那里修复了一些东西。最后一行打印出$sessionString,它是以引号分隔的所有会话列表。这部分有效。

      第二部分是事情变得奇怪的地方。您正在使用 $sessionString 并将其作为 SQL 语句传递。除非有什么我没有看到,$sessionString 只是一个会话列表,而不是一个 SQL 语句本身。

      正如我所说,检查每个 DBI 调用的错误,看看你是否在某个地方出错。

      你也可以像这样添加一行:

      print qq(DEBUG: SQL Query = '$sqlStatement'\n);
      

      在您运行$sth->prepare($sqlStatement) 之前,您可以看到您的 SQL 语句是什么。


      问题

      看起来您正在准备第二个查询,然后才弄清楚 (?) 应该是什么(我假设是您的 $sessionString 组)。

      您需要将会话替换为 (?)BEFORE 您执行 DBI->prepare()。

      类似这样的东西(未测试):

      (my $sessionQuery = $query) =~ s/\(\?\)/$sessionString/;
      my $querySth = $connect->prepare($sessionQuery);
      $querySth->execute();
      my @test = $queryPrep->fetchall_arrayref();
      

      请记住,qq() 引用语法是您的朋友。我经常使用这个:

      print qq(DEBUG: \$foo = "$foo"\n);
      

      有时,我只是复制并粘贴一个声明,然后引用它:

      print qq(DEBUG: while (my $foo = foobar($bar)) };\n);
      

      我能以这种方式捕捉到多少错误,真是令人惊讶。然后我可以在我的程序中搜索DEBUG: 并删除这些行。

      记住一次写一点你的程序,看看你能不能让$sessionString工作。然后尝试查看是否可以将其替换为您的 $query,然后尝试执行计算查询。

      Perl 是一门不错且功能强大的语言,但有时语法可能有点笨拙——尤其是如果您不习惯使用面向对象的 Perl。

      【讨论】:

      • "每次进行 DBI 调用时,都应该这样做:if ($sth->err())" 太难看了。您可以在 connect 方法调用中设置 RaiseError=>1 并且任何失败的方法都会死亡。
      • @bohica 是的,在过去的三年里,我已经将我的编程方法更改为基于异常的编程。当我编写模块时,如果出现问题,它们只会发出嘶哑的声音并且不再返回undefs。如果您不喜欢这样,请将电话放在eval 中。我现在在我的所有程序中都使用use autodie;。然而,主要的一点是你不应该盲目相信你从模块调用中得到的东西。如果它们基于异常,请将它们包装在eval 中,这样如果您想优雅地处理错误,就可以处理异常。
      猜你喜欢
      • 2017-12-15
      • 1970-01-01
      • 2016-01-10
      • 2012-09-05
      • 1970-01-01
      • 1970-01-01
      • 2018-09-23
      • 2023-01-25
      • 1970-01-01
      相关资源
      最近更新 更多