如何在不运行两个单独的进程调用的情况下获取DBI中的行数?

时间:2009-05-12 22:13:25

标签: perl dbi

我在Perl中运行DBI并且无法弄清楚当我运行预准备语句时,我可以判断返回的行数是否为0。

我意识到我可以在我的while循环中设置一个计数器来获取我的行,但我希望有一种不那么难看的方法。

12 个答案:

答案 0 :(得分:19)

基于快速查看here,似乎在您运行

之后
$statement->execute($arg)

您可以通过

访问行数
$statement->rows

答案 1 :(得分:11)

"caveat" in the documentation(与另一个答案的评论相关联)很重要,并提供真实,正确的答案:

  

通常,在 -SELECT执行后(对于某些特定操作,如UPDATE和DELETE),或者在获取SELECT语句的所有行之后,您只能依赖行计数。

     

对于SELECT语句,通常无法知道将返回多少行,除非通过全部获取它们。某些驱动程序将返回应用程序到目前为止所获取的行数,但其他驱动程序可能会返回-1,直到获取所有行为止。因此,不建议使用rows方法或带有SELECT语句的$ DBI :: rows。

答案 2 :(得分:9)

为了找出结果集中有多少行,您有两个选项:

  1. select count(*)
  2. 迭代结果集并计算行数。
  3. 你可以通过存储过程引入一些魔法,它返回一个数组或更奇特的东西,但最终需要发生这两件事之一。

    所以,没有花哨的方式来获得这个结果。你只需要计算它们: - )

答案 3 :(得分:4)

有点晚了,但是如果有人使用ORACLE,那么这就是汗水解决方案:

SELECT
  q.*,
  ROWNUM DB_ROWNUM,
  (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT
FROM
  ($sql) q
当然,

$ sql是你的查询。 Oracles优化器非常智能,不会执行所有操作。

现在,每个获取的行都包含DB_ROWNUM中的当前行号(对于分页网格行编号很有用)以及DB_COUNT中的完整行数。你仍然需要获取至少一行(因此它不完全是上述问题的答案;)),但接下来会出汗:

这也是在Oracle中启动和限制的一种非常简单的方法,并且仍然可以获得完整的行数:

SELECT * FROM (
  SELECT /*+ FIRST_ROWS($limit) */
    q.*,
    ROWNUM DB_ROWNUM,
    (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT
  FROM
    ($sql) q
  WHERE
    ROWNUM <= $limit
)
WHERE
  DB_ROWNUM > $start

这样,您实际上只能为网格中的第二页获取第51行到第100行,但仍然具有实际行号(从1开始)和每个获取行中的完整计数(没有开始和限制)。

答案 4 :(得分:2)

尝试此SQL解决方案,将数据的SQL与计数语句结合使用。

select null, null, null, count(*) from tablex
union
select foo, bar, foobar, null from tablex

第一个语句将具有计数,并且应该是第一行(如果不是,您可以通过它来绕过它),那么您可以在闲暇时循环记录其余部分。

答案 5 :(得分:2)

CPAN说:

  

[...]或在获取SELECT语句的所有行之后。

所以做这样的事情可能会奏效:

$sth->execute() or die $sth->errstr();
my $hasref = $sth->fetchall_hashref('id');
say "There is/are " .  scalar(keys(%{$hasref}) . " row(s).";

答案 6 :(得分:1)

我已动态生成SQL并执行它。对我来说select count(*)似乎不是一个选项,因为我必须再次重新生成查询。以下方法看起来很干净。但您必须再次发出s $h->execute()以检索行数据。

$h->execute() or die "ERROR: Couldn't execute SQL statement";
$rowcount_ref = $h->fetchall_arrayref(0);
$rowcount = scalar (@{$rowcount_ref});

- Shaakunthala

答案 7 :(得分:0)

行肯定会因看起来的数据库/驱动程序版本而异。我肯定会在那里找到一个处理意外结果的逻辑。

答案 8 :(得分:0)

如果您想知道在遍历所有行之前有多少行,则特定于MySQL的解决方案可以是FOUND_ROWS()

在第一次查询中,在SQL_CALC_FOUND_ROWS之后立即添加SELECT。然后执行SELECT FOUND_ROWS();,您就可以立即访问行数了。现在,您可以决定是要遍历所有行,还是最好的方法。

请注意,在查询中使用LIMIT将为您提供在没有LIMIT的情况下返回的查询总数。

答案 9 :(得分:0)

正如其他人已经说过的那样,你真的需要获取行来查明是否存在。如果在每行开始循环之前需要知道,并且预期结果不是很大,那么可以将所有结果都放到一个数组中,然后检查它。

我最近使用过这样的东西:

foreach my $table ( qw(ACTOR DIRECTOR PRODUCER WRITER) ) {
    my $sth = $dbi->prepare(qq{SELECT * FROM $table WHERE DESCRIPTION != TRIM(DESCRIPTION)})
        or die $dbi->errstr;
    $sth->execute or die $sth->errstr;

    my @rows = @{ $sth->fetchall_arrayref() };

    next unless @rows;

    foreach my $row (@rows) {
        print join(", ", map {qq("$_")} @{$row}), "\n";
    }
}

答案 10 :(得分:0)

我只是让数据库进行计数。如果您想要的只是行数。 找到2018年1月的所有行。

$year='2018';
my $qry = "SELECT COUNT(`my_key`) FROM `mtable` WHERE `my_date` LIKE '$year-01-%';";
my ($count) = $dbc->selectrow_array($qry);

答案 11 :(得分:0)

我认为使用引用可以很容易地实现这一点。 下面的代码展示了如何不需要重新执行查询以在计数后获取行。

my $sth = $dbh->prepare("SELECT NAME, LOCATION
                        FROM Employees"); 
$sth->execute() or die $DBI::errstr;

$nrows =  $sth->fetchall_arrayref() ;

print "Number of rows found :" . @$nrows . "\n";

#while (my @row = $sth->fetchrow_array()) {

foreach my $row(@{$nrows}) {
   my ($name, $location ) = @$row;
   print " Name = $name, Location = $location\n";
}

我希望这能满足这里提出的问题。