Как я могу проверить, даст ли запрос к базе данных результаты? - PullRequest
5 голосов
/ 14 ноября 2008

Наш веб-сайт использует Perl, чтобы предоставить нашим HR-сотрудникам простой механизм для размещения вакансий на нашем веб-сайте. Он был разработан третьей стороной, но с тех пор их давно связали, и, к сожалению, у нас нет никаких навыков в 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), который также будет включать мой оператор print. Но я бы предпочел использовать более простой подход If any records then print "We currently have.." line. К сожалению, я не имею ни малейшего понятия, чтобы закодировать даже эту простую строку.

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

1020 * ТИА *

Chris

Ответы [ 9 ]

15 голосов
/ 14 ноября 2008

Действительно простой способ будет:

$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";
}
3 голосов
/ 14 ноября 2008

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

$sth->execute();

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

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

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

3 голосов
/ 14 ноября 2008

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

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

Например, с макушки головы:

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

if ($#results == 0) {
  ... no results
} else {
  foreach $ref (@results) {
    my $temp = $template;
    ....
 }
2 голосов
/ 16 октября 2014

Поскольку ваш запрос представляет собой SELECT , вы не можете воспользоваться строками или значением, возвращаемым execute сама.

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

# 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";
2 голосов
/ 14 ноября 2008

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

$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";
}
1 голос
/ 14 ноября 2008
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) {
        ...
    }
}
1 голос
/ 14 ноября 2008

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

# 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);
1 голос
/ 14 ноября 2008

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

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;
}
0 голосов
/ 15 ноября 2008

Говорит 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;
 }
...