Como posso verificar se uma consulta de banco de dados irá retornar resultados?

StackOverflow https://stackoverflow.com/questions/290133

  •  08-07-2019
  •  | 
  •  

Pergunta

O nosso site usa Perl para fornecer um mecanismo simples para nossos pessoas de RH para vagas postar no nosso site. Ele foi desenvolvido por um terceiro, mas eles têm sido muito tempo desde que chutou em contato, e, infelizmente, não temos nenhuma habilidade Perl in-house. Isto é o que acontece quando as pessoas Marketing de aplicação da sua equipe interna de TI!

Eu preciso fazer uma mudança simples para esta aplicação. Atualmente, a página de vagas diz 'Atualmente, temos os seguintes vagas:', independentemente de se há vagas! Por isso, queremos mudá-lo de modo a que esta linha é exibida apenas nos momentos adequados.

Eu poderia, obviamente, começar a aprender um pouco de Perl, mas já estamos planejando um site de substituição, e certamente não estará usando Perl. Então, já que a solução será trivial para aqueles com essas habilidades, eu pensei que eu iria pedir alguma ajuda focada.

Abaixo está o início do procedimento que lista as vagas.

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

A linha de chave é while (my $ref = $sth->fetchrow_hashref()) {. Eu estou imaginando que este está dizendo 'enquanto eu pode retirar outra vaga a partir de registros retornado ...'. Se eu colocar a minha declaração de impressão antes desta linha, ele sempre será mostrado; depois desta linha e foi ser repetido para cada vaga.

Como faço para determinar que existem algumas vagas a serem exibidos, sem mover prematuramente através de registros retornado?

Eu sempre poderia copiar o código dentro do loop while, e colocá-lo dentro de uma instrução if () (que antecede a while), que também incluirá a minha declaração de impressão. Mas eu prefiro ter apenas a abordagem mais simples de If any records then print "We currently have.." line. Infelizmente, eu não tenho um indício de código ainda esta linha simples.

Veja, eu lhe disse que era um problema trivial, mesmo considerando a minha explicação atrapalhou!

TIA

Chris

Foi útil?

Solução

Uma maneira realmente simples seria:

$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";
}

Outras dicas

Se você estiver usando o MySQL, o método de "linhas" funciona muito bem:

$sth->execute();

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

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

O método, e algumas ressalvas, são documentados em muitos detalhes em "perldoc DBI". Sempre comece com "perldoc".

Isto não é tanto uma questão Perl porque é uma questão de banco de dados, e não há nenhuma boa maneira de saber quantos resultados você tem até que você tê-los. Você tem duas opções aqui:

  1. Faça uma consulta que faz um "select count (*)" para ver quantas linhas existem, e depois outra consulta para obter as linhas reais ou
  2. Faça a consulta e armazenar os resultados em um hash, em seguida, contar quantas entradas você tem no hash, e depois percorrer o hash e imprimir os resultados.

Por exemplo, em cima da minha cabeça:

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

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

Uma vez que todo mundo quer otimizar afastado os repetidos testes para saber se o cabeçalho foi impresso em solução de Graeme, apresento esta variação menor em que:

$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";
}

Desde sua consulta é um SELECT , você não pode tirar vantagem de linhas ou do valor retornado pelo executar si.

No entanto, você pode pré-contar quantas linhas (ou seja vagas) sua consulta irá selecionar adicionando outra consulta ... algo como isto:

# 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();

    ...
}

Ou, da mesma forma, em vez de "preparar" e "executar" a consulta e, em seguida, usar "fetchrow_array" , você pode fazer tudo em uma única chamada usando 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";

E o mesmo também é verdadeiro para 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";

No entanto, se você usar selectrow_array ou selectall_arrayref , você também pode recuperar o número de vagas diretamente do resultado da consulta original:

# 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";

Um pouco maneira mais eficiente (evitando uma condicional dentro do loop), se você não se importa que mudar a forma como a página é a saída de um pouco (de uma só vez, em vez de uma linha de cada vez), você poderia fazer uma variável para segurar a saída logo antes do loop:

my $output = '';

e, em seguida, dentro do loop, alterar qualquer declaração de impressão para esta aparência:

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

, em seguida, após o loop:

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

Basta adicionar outra consulta .. algo como isto:

# 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);
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) {
        ...
    }
}

Diz 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.

Portanto, a resposta é verificar o valor de retorno de US $ sth-> execute ():

 my $returnval = $sth->execute;
 if (defined $returnval && $returnval == 0) {
     carp "Query executed successfully but returned nothing";
     return;
 }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top