¿Cómo puedo verificar si una consulta de base de datos arrojará resultados?

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

  •  08-07-2019
  •  | 
  •  

Pregunta

Nuestro sitio web utiliza Perl para proporcionar un mecanismo simple para que nuestro personal de RR.HH. publique vacantes en nuestro sitio web. Fue desarrollado por un tercero, pero hace tiempo que se han puesto en contacto, y lamentablemente no tenemos ninguna habilidad de Perl internamente. ¡Esto es lo que sucede cuando el personal de marketing elude a su equipo de TI interno!

Necesito hacer un cambio simple a esta aplicación. Actualmente, la página de vacantes dice 'Actualmente tenemos las siguientes vacantes:', ¡independientemente de si hay vacantes! Por lo tanto, queremos cambiarlo para que esta línea solo se muestre en los momentos apropiados.

Podría, obviamente, comenzar a aprender un poco de Perl, pero ya estamos planeando un sitio de reemplazo, y ciertamente no usará Perl. Entonces, dado que la solución será trivial para aquellos con estas habilidades, pensé en pedir ayuda enfocada.

A continuación se muestra el inicio del procedimiento que enumera las vacantes.

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

La línea clave es while (my $ ref = $ sth- > fetchrow_hashref ()) {. Me imagino que esto está diciendo 'mientras puedo sacar otra vacante del conjunto de registros devuelto ...'. Si coloco mi declaración de impresión antes de esta línea, siempre se mostrará; después de esta línea y se repitió para cada vacante.

¿Cómo determino que hay algunas vacantes para mostrar, sin moverse prematuramente a través del conjunto de registros devuelto?

Siempre podría copiar el código dentro del ciclo while, y colocarlo dentro de una declaración if () (que precede al ciclo while) que también incluirá mi declaración de impresión. Pero prefiero tener el enfoque más simple de Si hay registros, imprima " Actualmente tenemos ... " línea . Desafortunadamente, no tengo ni idea de codificar incluso esta simple línea.

Mira, ¡te dije que era un problema trivial, incluso teniendo en cuenta mi torpe explicación!

TIA

Chris

¿Fue útil?

Solución

Una forma realmente simple sería:

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

Otros consejos

Si está utilizando Mysql, las " filas " El método funciona bien:

$sth->execute();

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

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

El método, y algunas advertencias, se documentan con gran detalle en "perldoc DBI". Comience siempre con " perldoc " ;.

Esta no es tanto una pregunta de Perl como una pregunta de base de datos, y no hay una buena manera de saber cuántos resultados tiene hasta que los tenga. Tienes dos opciones aquí:

  1. Haga una consulta que haga un " select count (*) " para ver cuántas filas hay, y luego otra consulta para obtener las filas reales o
  2. Realice la consulta y almacene los resultados en un hash, luego cuente cuántas entradas tiene en el hash, y luego revise el hash e imprima los resultados.

Por ejemplo, fuera de mi cabeza:

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

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

Dado que todos quieren optimizar las pruebas repetidas de si el encabezado se ha impreso en la solución de Graeme, presento esta pequeña variación:

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

Como su consulta es SELECCIONAR , no puede aprovechar filas o del valor devuelto por ejecutar en sí mismo.

Sin embargo, puede contar previamente cuántas filas (es decir, vacantes) seleccionará su consulta agregando otra consulta ... algo como esto:

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

    ...
}

O, de manera similar, en lugar de " preparar " y " ejecutar " la consulta y luego usar " fetchrow_array " , usted puede hacer todo en una sola llamada 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";

Y lo mismo también es cierto 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";

Sin embargo, si usa selectrow_array o selectall_arrayref , también puede recuperar el número de vacantes directamente del resultado de la 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";

Una manera un poco más eficiente (evitando un condicional dentro del bucle), si no le importa cambiar la forma en que la página se imprime un poco (todo a la vez en lugar de una fila a la vez) podría hacer una variable para mantener la salida justo antes del bucle:

my $output = '';

y luego dentro del bucle, cambie cualquier declaración de impresión para que se vea así:

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

luego después del ciclo:

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

Simplemente agregue otra consulta ... algo como esto:

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

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

Entonces, la respuesta es verificar el valor de retorno de $ sth- > execute ():

 my $returnval = $sth->execute;
 if (defined $returnval && $returnval == 0) {
     carp "Query executed successfully but returned nothing";
     return;
 }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top