Как я могу получить одно значение счетчика из базы данных с помощью DBI?

Следующий код кажется слишком большим для получения одного значения счетчика. Есть ли лучший рекомендуемый способ получить одно значение COUNT, используя простой DBI?

sub get_count {
   my $sth = $dbh->prepare("SELECT COUNT(*) FROM table WHERE...");
   $sth->execute( @params );
   my $($count) = $sth->fetchrow_array;
   $sth->finish;

   return $count;
}

Это короче, но у меня все еще есть два утверждения.

sub get_count_2 {
   my $ar = $dbh->selectall_arrayref("SELECT ...", undef, @params)
   return $ar->[0][0];
}

person szabgab    schedule 01.11.2009    source источник
comment
Это немного субъективно. Кто-то скажет, что ваш более длинный пример более удобочитаем. Мы играем в Perl Golf?   -  person pavium    schedule 01.11.2009
comment
Имеет ли значение, сколько у вас заявлений?   -  person brian d foy    schedule 01.11.2009
comment
У меня много таких вызовов в моем коде, поэтому у меня есть подпрограмма, которая получает оператор SQL и @params и возвращает количество. Если бы у меня был встроенный оператор для этого в DBI, мне не нужна дополнительная подпрограмма. Я думаю, что это распространенный вариант использования, и мне было интересно, было ли такое утверждение, и я его пропустил, или такого утверждения нет в DBI.   -  person szabgab    schedule 01.11.2009
comment
@szabgab Я не думаю, что это должно быть распространенным случаем. Для чего вы используете счет?   -  person Sinan Ünür    schedule 01.11.2009


Ответы (3)


Достаточно просто сделать в одну строку без дополнительных переменных:

$count = $dbh->selectrow_array('SELECT count(*) FROM table WHERE...', undef, @params);
person Dave Sherohman    schedule 01.11.2009
comment
Это то, что я искал. Спасибо! - person szabgab; 01.11.2009
comment
Документ сказал, что вы должны быть в контексте списка, лично я использую (my $count) = $dbh->selectrow_array('SELECT count(*) FROM table WHERE...', undef, @params); - person Gilles Quenot; 06.08.2013
comment
Контекст определяется правой частью присваивания, поэтому в любом случае он выполняется в контексте списка. Я просто воспользуюсь той деталью, что скалярное значение списка является последним элементом списка, в то время как вы явно захватываете первый элемент списка (что дает тот же результат, поскольку список в этом случае всегда будет содержать ровно один элемент). пункт). - person Dave Sherohman; 07.08.2013
comment
Контекст не определяется правой частью назначения (см. Контекстное руководство по PerlMonks). - person ThisSuitIsBlackNot; 09.01.2014
comment
Из документов DBI: при вызове в скалярном контексте для дескриптора оператора, который имеет более одного столбца, не определено, будет ли драйвер возвращать значение первого столбца или последнего. Так что не делай этого. Кроме того, в скалярном контексте возвращается undef, если строк больше нет или произошла ошибка. Этот undef нельзя отличить от возвращенного undef, потому что первое значение поля было NULL. По этим причинам вам следует проявлять некоторую осторожность, если вы используете selectrow_array в скалярном контексте или просто не делаете этого. - person ThisSuitIsBlackNot; 09.01.2014
comment
@ThisSuitIsBlackNot - Оглядываясь на это пять месяцев спустя, я понятия не имею, о чем я думал, когда сказал, что контекст определяется RHS ... Что касается цитаты из документов DBI, это хорошие общие предупреждения, но это конкретное случай, когда запрос всегда возвращает ровно одну строку, содержащую ровно один столбец, значение которого никогда не будет равным NULL, поэтому ни одна из перечисленных здесь проблем не применима. Я бы сказал, что это квалифицируется как проявление некоторой осторожности. - person Dave Sherohman; 10.01.2014

Я не знаю Perl, но если его синтаксис логичен, я думаю, что это сработает на основе вашего второго примера:

sub get_count {
   return $dbh->selectall_arrayref("SELECT ...", undef, @params)->[0][0];
}
person Tony Andrews    schedule 01.11.2009
comment
Хорошая догадка для тех, кто не знает Perl. :) - person friedo; 01.11.2009
comment
хорошо, хотя это должно быть $dbh->selectall_arrayref(SELECT ..., undef, @params)->[0][0]; поскольку вызов возвращает матрицу, а не вектор. (У меня была такая же ошибка в моем исходном примере, но я исправил ее после вашего комментария) - person szabgab; 01.11.2009

Я, вероятно, не стал бы делать это сам, но вы всегда можете сделать это новой функцией верхнего уровня используемого вами объекта DBH:

ВНИМАНИЕ: далее следует непроверенный код!

sub DBD::SQLite::db::count
{
   my($dbh, $table, $where) = @_;

   my($stmt) = "SELECT COUNT(*) FROM $table";
   $stmt .= " WHERE $where" if $where;

   my($count) = $dbh->selectrow_array($stmt);

   return $count;

}

а затем назовите это так:

my($cnt) = $dbh->count('Employee', 'year_hired < 2000');

Помимо загрязнения пространства имен, которое вам не принадлежит, вам также придется написать это для каждого используемого вами драйвера БД, хотя я уверен, что вы могли бы разработать что-то, что позволило бы вам создать и оценить некоторый код для автоматической настройки этого для данного объект ДБХ.

person Joe Casadonte    schedule 01.11.2009
comment
Помимо загрязнения чужого пространства имен и необходимости переписывать его для каждого используемого вами DBD, представленное решение требует от вас интерполяции значений в строку SQL вместо потери заполнителей ('year_hired ‹ ?'), поэтому вы теряете доступ к наилучшему из возможных защита от атак SQL-инъекций. - person Dave Sherohman; 02.11.2009
comment
Хорошая точка зрения; основная суть этого, однако, была в ответ на комментарий ОП. Если бы у меня был встроенный оператор для этого в DBI. - person Joe Casadonte; 02.11.2009