Как узнать, сколько строк возвращает запрос Perl DBI?

Я пытаюсь в основном выполнить поиск по базе данных с помощью Perl, чтобы узнать, есть ли элемент с определенным идентификатором. Этот поиск не может вернуть ни одной строки, но может и вернуть одну.

У меня есть следующий код:

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

По сути, это пытается увидеть, был ли возвращен идентификатор, и если это не так, продолжить работу со сценарием. Но он выдает ошибку ссылки массива Null на вещь $th->fetch()->[0]. Как я могу просто проверить, вернул ли он строки или сейчас?


person The.Anti.9    schedule 13.01.2009    source источник
comment
Это действительно больше связано с библиотекой, которую вы используете... возможно, вы сможете обновить свой вопрос, чтобы он был более конкретным.   -  person Robert P    schedule 14.01.2009
comment
@ Роберт, это не имеет ничего общего с библиотекой, которую он использует. Все драйверы ODBC действуют одинаково.   -  person Paul Tomblin    schedule 14.01.2009
comment
Я надеюсь, что это просто пример кода. Но вы должны использовать значения привязки.   -  person innaM    schedule 14.01.2009


Ответы (7)


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();
person Paul Tomblin    schedule 13.01.2009

Драйвер DBD::mysql имеет метод rows(), который может возвращать число результатов. :

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

Это зависит от драйвера базы данных, поэтому он может не работать в других драйверах или может работать по-другому в других драйверах.

person brian d foy    schedule 13.01.2009
comment
В DBI есть метод rows(), но rows() не возвращает значимого результата для SELECT во многих DBD, пока не будут выбраны все строки. - person runrig; 14.01.2009
comment
Здесь мы говорим о конкретном DBD. :) - person brian d foy; 14.01.2009
comment
А, теперь я вижу это... скрыто в тегах узла... оно должно быть в заголовке или тексте, если это важная часть вопроса :-) - person runrig; 14.01.2009

Почему бы вам просто не «выбрать количество (*) ...» ??

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

Или чтобы помешать Little Bobby Tables:

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);
person runrig    schedule 13.01.2009

Изменить select, чтобы всегда что-то возвращать? Это должно работать в Sybase, не знаю, как в других БД.

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

В общем, я не уверен, почему люди так боятся исключений. Вы ловите их и идете дальше.

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."         }

Однако в этом случае ответ Пола является лучшим.

Кроме того, $sth->rows обычно не работает, пока вы не извлечете каждую строку. Если вы хотите узнать, сколько строк совпадает, вам нужно задать механизму базы данных вопрос, на который вы хотите получить ответ; а именно select count(1) from foo where bar='baz'.

person jrockway    schedule 13.01.2009

Единственный надежный способ узнать, сколько строк возвращается запросом 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
}
person Dave Sherohman    schedule 13.01.2009
comment
... в любом случае вам почти никогда не нужно знать это заранее - для очень распространенного случая разбиения результатов на страницы вам нужно будет заранее знать, сколько результатов есть. - person Lee Goddard; 07.11.2012
comment
И мне нравится видеть, сколько записей моя программа прочитала/обработала из общего числа выбранных записей. Если мой выбор захватил 10 000 записей и обрабатывает 100 записей в минуту, это займет некоторое время. - person Bulrush; 02.11.2017

В этой статье пользователи 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. Вам все еще нужно выполнить второй запрос, чтобы получить количество строк, но это простой запрос и не такой сложный, как ваш запрос, который извлек данные.

Использование довольно простое. В основной запрос вам нужно добавить параметр SQL_CALC_FOUND_ROWS сразу после SELECT, а во втором запросе вам нужно использовать функцию FOUND_ROWS(), чтобы получить общее количество строк. Запросы будут выглядеть так:

SELECT SQL_CALC_FOUND_ROWS имя, электронная почта FROM пользователей WHERE имя LIKE 'a%' LIMIT 10;

ВЫБЕРИТЕ FOUND_ROWS();

Единственное ограничение состоит в том, что вы должны вызывать второй запрос сразу после первого, потому что SQL_CALC_FOUND_ROWS нигде не сохраняет количество строк.

Хотя это решение также требует двух запросов, оно намного быстрее, так как вы выполняете основной запрос только один раз.

Вы можете прочитать больше о SQL_CALC_FOUND_ROWS и FOUND_ROWS() в документации по MySQL.

К сожалению, с 8.0.17:

Модификатор запроса SQL_CALC_FOUND_ROWS и сопутствующая функция FOUND_ROWS() устарели, начиная с MySQL 8.0.17...

Подробности здесь.

person Lee Goddard    schedule 07.11.2012