Как я могу проверить, возвращает ли запрос к базе данных результаты?

Наш веб-сайт использует Perl, чтобы предоставить нашим сотрудникам отдела кадров простой механизм для размещения вакансий на нашем веб-сайте. Он был разработан третьей стороной, но они уже давно были вовлечены в контакт, и, к сожалению, у нас нет собственных навыков Perl. Вот что происходит, когда маркетологи обходят своих штатных ИТ-специалистов!

Мне нужно внести простые изменения в это приложение. В настоящее время на странице вакансий написано «В настоящее время у нас есть следующие вакансии:», независимо от того, есть ли какие-либо вакансии! Поэтому мы хотим изменить его так, чтобы эта строка отображалась только в подходящее время.

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

Ниже приводится начало процедуры составления списка вакансий.

sub list {
  require HTTP::Date;
  import HTTP::Date;

  my $date = [split /\s+/, HTTP::Date::time2iso(time())]->[0];

  my $dbh = DBI->connect($dsn, $user, $password)
    || die "cannot connect to $database: $!\n";

  my $sql = <<EOSQL;
SELECT * FROM $table where expiry >= '$date' order by expiry
EOSQL

  my $sth = $dbh->prepare($sql);
  $sth->execute();


  while (my $ref = $sth->fetchrow_hashref()) {
    my $temp  = $template;
    $temp     =~ s#__TITLE__#$ref->{'title'}#;

    my $job_spec = $ref->{'job_spec'};

...etc...

Ключевая линейка - while (my $ref = $sth->fetchrow_hashref()) {. Я полагаю, что это говорит «пока я могу снять еще одну вакансию из возвращенного набора записей ...». Если я помещаю свой оператор печати перед этой строкой, он всегда будет отображаться; после этой строки и повторяется для каждой вакансии.

Как определить, есть ли какие-то вакансии, которые нужно отобразить, без преждевременного просмотра возвращенного набора записей?

Я всегда мог скопировать код внутри цикла while и поместить его в оператор if () (предшествующий циклу while), который также будет включать мой оператор печати. Но я бы предпочел использовать более простой подход If any records then print "We currently have.." line. К сожалению, я понятия не имею, как кодировать даже эту простую строчку.

Видите ли, я сказал вам, что это тривиальная проблема, даже с учетом моих неуклюжих объяснений!

TIA

Крис

Обратите внимание, что require автоматически умирает для вас, если он терпит неудачу, поэтому я немного изменил это, чтобы никто не мог скопировать и вставить это в свой код. :)

brian d foy 14.11.2008 23:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
13 439
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Это не столько вопрос Perl, сколько вопрос базы данных, и нет хорошего способа узнать, сколько результатов у вас есть, пока вы их не получите. У вас есть два варианта:

  1. Выполните запрос, который выполняет «счетчик выбора (*)», чтобы узнать, сколько строк имеется, а затем другой запрос, чтобы получить фактические строки или
  2. Выполните запрос и сохраните результаты в хеше, затем подсчитайте, сколько записей у вас есть в хеше, а затем просмотрите хеш и распечатайте результаты.

Например, с головы до ног:

my @results = ();
while (my $ref = $sth->fetchrow_hashref()) {
   push @results, $ref;
}

if ($#results == 0) {
  ... no results
} else {
  foreach $ref (@results) {
    my $temp = $template;
    ....
 }

если вы собираетесь это сделать, вы можете просто заменить цикл чтения на @results = @ {$ sth-> fetchall_arrayref ({})};

ysth 14.11.2008 20:54

$ # результатов будет 0, если есть один результат. Пожалуйста, не используйте массив $ #, если вы не уверены, что вам это нужно. В большинстве случаев @array в скалярном контексте - это то, что вам нужно.

ysth 14.11.2008 20:55

@ysth - Ну, я же сказал, что это было не в моей голове. Будет ли скаляр (@array) делать то, что я хочу?

Paul Tomblin 14.11.2008 21:00

Другая проблема заключается в том, что если в результате появляются тысячи (или сотни тысяч) строк, возможно, вы не захотите хранить их все в памяти одновременно.

Graeme Perrow 14.11.2008 21:09

@Graeme: Если он не работает на monster.com, я сомневаюсь, что у него есть тысячи открытых вакансий.

Paul Tomblin 14.11.2008 22:04

@Paul: scalar (@array) вернет количество элементов в массиве, да, но в этом случае достаточно просто проверки 'if (@array) ...' и, IMO, более читаемым, чем явная скаляризация. .

Dave Sherohman 14.11.2008 22:09

@Dave - Мне никогда не нравилась эта "контекстная" особенность Perl. Я думаю, что яснее изложить это прямо.

Paul Tomblin 14.11.2008 22:55

@ Пол: Да, в данном конкретном случае это не проблема. Я имел в виду общий случай.

Graeme Perrow 15.11.2008 00:49

@ Пол: Честно говоря, многим это не нравится. Моя точка зрения заключалась скорее в том, что концептуально вы здесь ищете, есть ли что-нибудь в массиве (if (@array)), а не количество элементов, которые он содержит (if (scalar (@array)! = 0) ). Но, как всегда, TIMTOWTDI.

Dave Sherohman 15.11.2008 20:58
Ответ принят как подходящий

Очень простой способ:

$sth->execute();

my $first = 1;
while (my $ref = $sth->fetchrow_hashref()) {
    if ( $first ) {
        print "We currently have the following vacancies:\n";
        $first = 0;
    }
    my $temp  = $template;
    ...
}
if ( $first ) {
    print "No vacancies found\n";
}

Или вы можете проверить возвращаемое значение $ sth-> execute (), которое заранее сообщает вам, будут ли вообще какие-либо данные.

Sam Kington 15.11.2008 07:29

@SamKington: возвращаемое значение $ sth-> execute () возвращает количество затронутых строк ТОЛЬКО для операторов, отличных от SELECT. См .: search.cpan.org/~timb/DBI-1.631/DBI.pm#execute

Paolo Rovelli 05.09.2014 16:05

Немного более эффективный способ (избегая условного выражения внутри цикла), если вы не возражаете, чтобы он немного изменил способ вывода страницы (все сразу, а не по строкам), вы можете создать переменную для хранения вывод непосредственно перед циклом:

my $output = '';

а затем внутри цикла измените любой оператор печати, чтобы он выглядел так:

$output .= "whatever we would have printed";

затем после цикла:

if ($output eq '')
{
  print 'We have no vacancies.';
}
else
{
  print "We currently have the following vacancies:\n" . $output;
}

Если они не Google, у них, вероятно, не может быть больше, чем несколько или несколько десятков вакансий в любое время, поэтому стоимость условного объявления ничтожна по сравнению со стоимостью отрисовки страницы. Я все еще голосую за решение @ Graeme.

Paul Tomblin 14.11.2008 17:06

Конечно, но если код будет повторно использован в другом контексте, хорошо подумать.

Kev 14.11.2008 17:09

Я уверен, что код будет повторно использован во многих местах, но не нами! :) Но я ценю ваше мнение - это было бы разумно как подход «хорошей практики».

CJM 14.11.2008 17:12

Я также не уверен, что выполнение операции конкатенации строк более эффективно, чем сравнение. Это определенно то, что потребует тестирования, если вы действительно хотите нарушить первое правило Optimization Club.

Paul Tomblin 14.11.2008 17:18

Согласовано. Для большого набора данных я также ожидал бы, что конкатенации (с соответствующими требованиями к выделению памяти и копированию строк) будут существенно менее эффективными, чем выполнение теста.

Dave Sherohman 14.11.2008 22:11

Просто добавьте еще один запрос .. примерно так:

# count the vacancies    
$numinfo = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE EXPIRY >= ?");
$numinfo->execute($date);
$count = $numinfo->fetchrow_arrayref()->[0];

# print a message
my $msg = '';
if   ($count == 0) $msg = 'We do not have any vacancies right now';
else               $msg = 'We have the following vacancies';
print($msg);

Если вы используете Mysql, метод "строк" работает нормально:

$sth->execute();

if ($sth->rows) {
  print "We have data!\n";
}

while(my $ref = $sth->fetchrow_hashref()) {
...
}

Метод и некоторые предостережения подробно описаны в "perldoc DBI". Всегда начинайте с perldoc.

Вы не можете полагаться на $ sth-> rows для запросов SELECT (как рассматриваемый). См .: search.cpan.org/~timb/DBI-1.631/DBI.pm#rows

Paolo Rovelli 05.09.2014 16:24
use Lingua::EN::Inflect 'PL';

$sth->execute();
my $results = $sth->fetchall_arrayref( {}, $max_rows );

if (@$results) {
    print "We currently have the following ", PL("vacancy",scalar @$results), ":\n";

    for my $ref (@$results) {
        ...
    }
}

Он различает один vacancy и несколько vacancйес.

Dave Sherohman 14.11.2008 22:12

И я не вижу других решений с использованием fetchall_arrayref.

ysth 16.11.2008 05:55

Поскольку каждый хочет оптимизировать повторные тесты для проверки того, был ли напечатан заголовок в решении Грэма, я представляю его небольшую вариацию:

$sth->execute();

my $ref = $sth->fetchrow_hashref();
if ($ref) {
  print "We currently have the following vacancies:\n";
  while ($ref) {
    my $temp  = $template;
    ...
    $ref = $sth->fetchrow_hashref();
  }
} else {
    print "No vacancies found\n";
}

Perldoc DBI говорит:

 For a non-"SELECT" statement, "execute" returns the number of rows
 affected, if known. If no rows were affected, then "execute"
 returns "0E0", which Perl will treat as 0 but will regard as true.

Итак, ответ - проверить возвращаемое значение $ sth-> execute ():

 my $returnval = $sth->execute;
 if (defined $returnval && $returnval == 0) {
     carp "Query executed successfully but returned nothing";
     return;
 }

perldoc специально говорит «Для оператора, отличного от SELECT», и в вопросе есть оператор SELECT.

Graeme Perrow 15.11.2008 15:41

Поскольку ваш запрос представляет собой ВЫБРАТЬ, вы не можете использовать ряды или значение, возвращаемое самим выполнять.

Однако вы можете заранее подсчитать, сколько строк (т.е. вакансий) выберет ваш запрос, добавив еще один запрос ... примерно так:

# Retrieve how many vacancies are currently offered:
my $query = "SELECT COUNT(*) AS rows FROM $table WHERE expiry >= ?";
$sth = $dbh->prepare($query);
$sth->execute($date);
$numVacancies = $numinfo->fetchrow_arrayref()->[0];

# Debug:
print "Number of vacancies: " . $numVacancies . "\n";

if ( $numVacancies == 0 ) { # no vacancy found...
    print "No vacancies found!\n";
}
else { # at least a vacancy has been found...
    print "We currently have the following vacancies:\n";

    # Retrieve the vacancies:
    my $sql = "SELECT * FROM $table where expiry >= '$date' ORDER BY expiry";
    my $sth = $dbh->prepare($sql);
    $sth->execute();

    ...
}

Или, аналогично, вместо "подготовить" и "выполнять" запроса, а затем использования "fetchrow_array", вы можете сделать все за один вызов, используя selectrow_array:

# Retrieve how many vacancies are currently offered:
my $query = "SELECT COUNT(*) AS rows FROM $table WHERE expiry >= ?"; 
my $numVacancies = $dbh->selectrow_array($query, undef, $date);

# Debug:
print "Number of vacancies: " . $numVacancies . "\n";

То же самое и для selectall_arrayref:

# Retrieve how many vacancies are currently offered:
my $query = "SELECT COUNT(*) AS rows FROM $table WHERE expiry >= ?";
my $numVacancies = $dbh->selectall_arrayref($query, {Slice => {}}, $date);

# Debug:
print "Number of vacancies: " . @$numVacancies[0]->{rows} . "\n";

Однако, если вы используете selectrow_array или selectall_arrayref, вы также можете получить количество вакансий непосредственно из результата исходного запроса:

# Retrieve the vacancies:
my $sql = "SELECT * FROM $table where expiry >= ? ORDER BY expiry";
my $vacancies = $dbh->selectall_arrayref($sql, {Slice => {}}, $date);

# Debug:
print "Number of vacancies: " . scalar @{$vacancies} . "\n";

Другие вопросы по теме