我该如何知道Perl DBI查询返回了多少行?

20

我想用Perl在数据库中进行搜索,以确定是否存在具有特定ID的项目。这个搜索可能不返回任何行,但也可能返回一行。

我有以下代码:

my $th = $dbh->prepare(qq{SELECT bi_exim_id FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
if ($th->fetch()->[0] != $exid) {
        ...

基本上,这个代码尝试检查ID是否被返回,如果没有返回,则继续执行脚本。但是,在$th->fetch()->[0]处出现了一个空数组引用错误。

我该如何简单地检查它返回了行还是没有返回?


这其实更多与你正在使用的库有关... 你可以更新你的问题以使其更具体。 - Robert P
@Robert,这与他使用的库无关。所有ODBC驱动程序都是相同的。 - Paul Tomblin
1
我希望这只是示例代码。但你应该使用绑定值。 - innaM
7个回答

38

DBD::mysql 驱动程序有一个 rows() 方法,可以返回结果的数量:

$sth = $dbh->prepare( ... );
$sth->execute;
$rows = $sth->rows;

这是特定于数据库驱动程序的,因此在其他驱动程序中可能无法正常工作,或在其他驱动程序中可能会有所不同。


1
DBI有rows()方法,但在许多DBD中,对于SELECT语句,rows()在所有行都被提取之前不会返回有意义的结果。 - runrig
4
我们在这里谈论的是特定的DBD。 :) - brian d foy
2
啊,我现在看到了……它隐藏在节点的标签中……如果那是问题的重要部分,它应该在标题或正文中。 :-) - runrig

13
my $th = $dbh->prepare(qq{SELECT bi_exim_id FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
my $found = 0;
while ($th->fetch()) 
{
   $found = 1;
}

如果行不存在,你的查询将不会返回任何东西,因此你无法引用提取的内容。

更新: 你可能想要重新写成:

my $found = $th->fetch();

5
为什么你不直接使用 "select count(*) ..." 语句呢?
my ($got_id) = $dbh->selectrow_array("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = '$exid'");

或者为了防止小博比表的攻击:

my $q_exid = $dbh->quote($exid);
my ($got_id) = $dbh->selectrow_array("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = $q_exid");

如果你需要频繁执行此操作:

my $sth = $dbh->prepare("SELECT count(*) from FROM bounce_info WHERE bi_exim_id = ?");
....save $sth (or use prepare_cached()) and then later
my ($got_id) = $dbh->selectrow_array($sth, undef, $exid);

4

将 select 改为始终返回结果?这在 Sybase 中应该可以工作,不确定其他数据库是否也适用。

my $th = $dbh->prepare(qq{SELECT count(*) FROM bounce_info WHERE bi_exim_id = '$exid'});
$th->execute();
if ($th->fetch()->[0]) {
....
}

2

总的来说,我不确定为什么人们如此害怕异常。你捕获它们然后继续执行。

my $sth = prepare ...
$sth->execute;
my $result = eval { $sth->fetchrow_arrayref->[1] };

if($result){ say "OH HAI. YOU HAVE A RESULT." }
else       { say "0 row(s) returned."         }

在这种情况下,Paul的答案最好。此外,$sth->rows通常在你获取每一行之前是不起作用的。如果你想知道有多少行匹配,则必须向数据库引擎实际询问你想要知道答案的问题;即select count(1) from foo where bar='baz'

1
找出SELECT查询返回的行数的唯一可靠方法是获取所有行并计数。如DBI文档所述:
“通常,您只能在非SELECT执行(对于某些特定操作,如UPDATE和DELETE)或获取SELECT语句的所有行之后才能依赖行计数。
对于SELECT语句,通常不可能知道将返回多少行,除非获取它们全部。一些驱动程序将返回应用程序到目前为止获取的行数,但其他驱动程序可能会返回-1,直到获取了所有行。因此,不建议使用rows方法或$DBI::rows与SELECT语句。”
然而,当你深入研究时,你几乎从来不需要提前知道这个。只需循环while ($sth->fetch)处理每一行,或者对于仅返回零或一行的查询的特殊情况,可以这样做。
if ($sth->fetch) {
  # do stuff for one row returned
} else {
  # do stuff for no rows returned
}

1
“...你几乎从来不需要提前知道那个”-- 对于非常普遍的结果分页情况,您需要提前知道有多少结果。 - Lee Goddard
我喜欢看到我的程序已读/处理了多少记录,以及所选记录的总数。如果我的选择抓取了10,000条记录,并且每分钟处理100条记录,那将需要一段时间。 - Bulrush

1

本文适用于MySQL 8版本之前的用户:

http://www.arraystudio.com/as-workshop/mysql-get-total-number-of-rows-when-using-limit.html

幸运的是,自MySQL 4.0.0以来,您可以在查询中使用SQL_CALC_FOUND_ROWS选项,告诉MySQL忽略LIMIT子句计算总行数。您仍然需要执行第二个查询以检索行计数,但它是一个简单的查询,不像检索数据的查询那样复杂。
使用方法非常简单。在主查询中,您需要在SELECT之后添加SQL_CALC_FOUND_ROWS选项,在第二个查询中,您需要使用FOUND_ROWS()函数获取总行数。查询如下所示:
SELECT SQL_CALC_FOUND_ROWS name, email FROM users WHERE name LIKE 'a%' LIMIT 10; SELECT FOUND_ROWS();
唯一的限制是必须在第一个查询之后立即调用第二个查询,因为SQL_CALC_FOUND_ROWS不会将行数保存在任何地方。
尽管此解决方案也需要两个查询,但它比较快,因为您只执行一次主查询。
您可以在MySQL文档中阅读有关SQL_CALC_FOUND_ROWS和FOUND_ROWS()的更多信息。
不幸的是,在8.0.17版本中,SQL_CALC_FOUND_ROWS查询修饰符和相应的FOUND_ROWS()函数已被弃用...

详情请点击此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接