我在 Perl 中运行 DBI,但无法弄清楚当我运行准备好的语句时,我如何知道返回的行数是否为 0。
我意识到我可以在我的 while 循环中设置一个计数器来获取我的行,但我希望有一种不那么丑陋的方法来做到这一点。
文档中的“警告”(链接到另一个答案的评论中)很重要,并提供了真实、正确的答案:
通常,您只能在非-SELECT 执行(对于某些特定操作,如 UPDATE 和 DELETE)之后或在获取 SELECT 语句的所有行之后依赖行计数。
对于 SELECT 语句,通常不可能知道将返回多少行,除非全部获取它们。一些驱动程序将返回应用程序到目前为止已获取的行数,但其他驱动程序可能会返回 -1,直到所有行都已获取。因此不推荐使用带有 SELECT 语句的 rows 方法或 $DBI::rows。
为了找出结果集中有多少行,您有两个选项:
select count(*)
您可以通过返回数组或更花哨的存储过程引入一些魔法,但最终需要发生这两件事中的一件。
所以,没有花哨的方法来获得这个结果。你只需要数一数:-)
有点晚了,但是如果有人使用 ORACLE,那么汗水解决方案来了:
SELECT
q.*,
ROWNUM DB_ROWNUM,
(SELECT max(ROWNUM) FROM ($sql)) DB_COUNT
FROM
($sql) q
当然,$sql 是您的查询。Oracles 优化器足够智能,不会执行所有操作两次。
现在,每个获取的行都在 DB_ROWNUM 中保存当前行号(对分页网格行编号有用),在 DB_COUNT 中保存完整的行数。您仍然必须获取至少一行(因此它不完全是上述问题的答案;)),但接下来是汗水使用:
这也是在 Oracle 中进行 start 和 limit 并仍然获得完整行数的一种非常简单的方法:
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 开始)和完整的计数(没有开始和限制)。
试试这个 SQL 解决方案,将数据的 SQL 与 count 语句结合起来。
从 tablex 中选择 null、null、null、count(*) 联盟 从 tablex 中选择 foo、bar、foobar、null
第一条语句将具有计数,并且应该是第一行(如果不是,您可以订购绕过它)然后您可以在闲暇时循环浏览记录集的其余部分。
CPAN 说:
[...] 或在获取 SELECT 语句的所有行之后。
所以做这样的事情可能会奏效:
$sth->execute or die $sth->errstr;
say (scalar keys %{$sth->fetchall_hashref('id')}) . ' row(s).';
我已经动态生成了一个 SQL 并执行它。对我来说select count(*)
似乎不是一个选择,因为我必须再次重新生成查询。以下方法对我来说看起来很干净。但是您必须$h->execute()
再次发出 s 才能检索行数据。
$h->execute() or die "ERROR: Couldn't execute SQL statement";
$rowcount_ref = $h->fetchall_arrayref(0);
$rowcount = scalar (@{$rowcount_ref});
——沙昆塔拉
行肯定会根据看起来的数据库/驱动程序版本而有所不同。我肯定会在那里寻找一个处理意外结果的逻辑。
我只是让数据库进行计数。如果你想要的只是行数。查找 2018 年 1 月的所有行。
$year='2018';
my $qry = "SELECT COUNT(`my_key`) FROM `mtable` WHERE `my_date` LIKE '$year-01-%';";
my ($count) = $dbc->selectrow_array($qry);
我认为这可以很容易地使用引用来实现。下面的代码显示了如何不需要重新执行查询来获取计数后的行。
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";
}
我希望这能满足这里提出的问题。
如果您想在遍历所有行之前知道有多少行,特定于 MySQL 的解决方案可能是FOUND_ROWS()。
在您的第一个查询中,SQL_CALC_FOUND_ROWS
在SELECT
. 然后执行SELECT FOUND_ROWS();
,您可以立即访问行数。现在您可以决定是否要遍历所有行,或者最好的方法。
请注意,LIMIT
在查询中包含 将为您提供不带LIMIT
.
正如其他人已经说过的那样,您确实需要获取行以找出是否有任何行。如果您需要在对每一行开始循环之前知道,并且如果预期结果不是很大,您可以将所有结果放入一个数组中,然后检查。
我最近使用了类似的东西:
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";
}
}