2008-11-14 8 views
5

Nuestro sitio web utiliza Perl para proporcionar un mecanismo simple para que nuestra gente de recursos humanos publique vacantes en nuestro sitio web. Fue desarrollado por un tercero, pero desde hace mucho tiempo han sido pateados al tacto, y lamentablemente no tenemos ninguna habilidad Perl internamente. ¡Esto es lo que ocurre cuando las personas de Marketing se burlan de su equipo de TI interno!¿Cómo puedo verificar si una consulta de base de datos arrojará resultados?

Necesito hacer un cambio simple en 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 adecuados.

Podría, obviamente, empezar 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é que pediría ayuda enfocada.

A continuación se muestra el comienzo 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 de la clave es while (my $ref = $sth->fetchrow_hashref()) {. Me imagino que esto está diciendo 'mientras puedo obtener otra vacante del conjunto de registros devuelto ...'. Si coloco mi extracto 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 puedo determinar si hay vacantes para mostrar, sin desplazarme prematuramente por el conjunto de registros devuelto?

Siempre pude copiar el código dentro del ciclo while, y colocarlo dentro de una instrucción if() (que precede al ciclo while) que también incluirá mi declaración de impresión. Pero preferiría tener el enfoque más simple de If any records then print "We currently have.." line. 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 explicación a tientas!

TIA

Chris

+0

Nota que requieren muere automáticamente si se produce un error, así que cambié eso un poco para que nadie pueda copiarlo y pegarlo en su código. :) –

Respuesta

15

Una forma muy 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"; 
} 
+0

O puede verificar el valor de retorno de $ sth-> execute(), que le informa por adelantado si va a haber algún dato. –

+0

@SamKington: el valor de retorno de $ sth-> execute() devuelve el número de filas afectadas SÓLO para las instrucciones que no son SELECT. Ver: http://search.cpan.org/~timb/DBI-1.631/DBI.pm#execute –

3

Esto no es tanto una cuestión de Perl, ya que es una pregunta de base de datos, y no hay buena manera de saber cuántos resultados que tiene hasta que los tiene. Tienes dos opciones aquí:

  1. hacer una consulta que realiza una "select count (*)" para ver cuántas filas hay, y luego otra consulta para obtener las filas reales o
  2. hacer lo consulte y almacene los resultados en un hash, luego cuente cuántas entradas tiene en el hash, y luego pase por el hash e imprima los resultados.

Por ejemplo, la parte superior 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; 
    .... 
} 
+0

si va a hacer eso, también puede simplemente reemplazar el ciclo de lectura con @results = @ {$ sth-> fetchall_arrayref ({})}; – ysth

+0

$ # resultados serán 0 cuando hay un resultado. No use $ # array a menos que esté seguro de que lo necesita. La mayoría de las veces, @array en contexto escalar es lo que quieres en su lugar. – ysth

+0

@ysth - Bueno, dije que estaba fuera de mi cabeza. ¿Scalar (@array) haría lo que yo quiero? –

1

manera un poco más eficiente (evitando un condicional dentro del bucle) , si no le molesta cambiar la forma en que la página sale un poco (todo a la vez en vez de una fila a la vez), puede crear una variable para mantener la salida justo antes del ciclo:

my $output = ''; 

y luego dentro del bucle, cambiar cualquier declaración de impresión para tener este aspecto:

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

continuación, después del bucle:

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

A menos que sean Google, probablemente no tengan más que unas pocas o pocas docenas de vacantes en cualquier momento, por lo que el costo de un condicional es minúsculo en comparación con el costo de renderizar la página. Aún voto por la solución de @ Graeme. –

+0

Claro, pero si el código pasa a ser reutilizado en otro contexto, es bueno pensar en ello. – Kev

+0

¡Estoy seguro de que el código se volverá a usar en muchos lugares, pero no por nosotros! :) Pero aprecio sus sentimientos, tendría sentido como un enfoque de 'buena práctica'. – CJM

1

simplemente añada 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); 
3

Si está utilizando Mysql, el método de "filas" 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 en gran detalle en "perldoc DBI". Siempre comience con "perldoc".

+0

No puede confiar en $ sth-> filas para consultas SELECT (como la que está en cuestión). Ver: http://search.cpan.org/~timb/DBI-1.631/DBI.pm#rows –

1
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) { 
     ... 
    } 
} 
+0

Diferencia entre un solo vacanc * y * y múltiples vacanc * ies *. –

+0

Y no veo ninguna otra solución usando fetchall_arrayref. – ysth

2

Puesto que cada uno quiere optimizar la distancia de las repetidas pruebas de si la cabecera ha sido impreso en solución de Graeme, presento esta variación menor en él:

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

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. 

Así que la respuesta es comprobar el valor de retorno de $ sth-> execute():

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

perldoc dice específicamente "Para una declaración que no es SELECT", y la pregunta tiene una instrucción SELECT en ella. –

1

Dado que su consulta es SELECCIONE, no puede tomar ventaja de rows o del valor devuelto por el execute.

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, del mismo modo, en lugar de "preparar" y "ejecutar" la consulta y luego usar "fetchrow_array", se 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 es también 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 se utiliza 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"; 
Cuestiones relacionadas