2010-11-09 6 views
1

DISCLAIMER - Très nouveau à Perl -Exécuter la requête DBI avec une chaîne concatonated

Je dois passer une chaîne concaténée de sessions à une requête préparée qui ressemble à ceci

my $uniqueSessions="SELECT DISTINCT SESSION 
        FROM $table"; 

my $queryUniques = $connect->prepare($uniqueSessions); 
$queryUniques->execute(); 
$queryUniques->bind_columns(\$session); 

my $query="SELECT session, action 
      FROM  $table 
      WHERE session 
      IN  (?) 
      ORDER BY session, id"; 

my $queryPrep = $connect->prepare($query); 

while($queryUniques->fetch()) { 
    if($counter == 1) { 
     $sessionString = "'" . $session . "'"; 
    } else { 
     $sessionString = $sessionString . ", '" . $session . "'"; 
    } 

    $counter++; 
    if(($counter % 5) == 0) { 
     $counter = 1; 
     $queryPrep->execute($sessionString); 
     my @test = $queryPrep->fetchall_arrayref(); 
    } 
} 

Pourtant, c'est ne rien retourner, et j'ai essayé la requête exacte dans mon client DB et ça fonctionne, des idées?

EDIT: Désolé semble avoir trop coupé J'ai modifié le code pour s'assurer que toutes les informations étaient présentes;

La chaîne renvoyée est des sessions entre guillemets simples avec une virgule entre.

Répondre

1

Comme d'autres l'ont dit:

use strict; 
use warnings; 

En outre, chaque fois que vous faites un appel DBI, vous devez faire ceci:

if ($sth->err()) { 
    die "ERROR: " . $sth->errstr() . "\n"; 
} 

Même après une extraction. Cela permettra d'attraper beaucoup de problèmes que vous pourriez avoir.

I simplifié votre programme un petit peu:

use strict; 
use warnings; 

use DBI; 

my $connect = DBI->connect("$connectString", "$user", "$id"); 

if (not $connect) { 
die qq(connection error\n); 
} 

my $table = "session"; 
my $uniqueSessions = "SELECT DISTINCT SESSION 
     FROM $table"; 

print qq(\$uniqueSessions = "$uniqueSessions"\n); 

my $queryUniques = $connect->prepare($uniqueSessions); 
if ($queryUniques->err()) { 
die "ERROR: " . $queryUniques->errstr() . "\n"; 
} 
$queryUniques->execute(); 
if ($queryUniques->err()) { 
die "ERROR: " . $queryUniques->errstr() . "\n"; 
} 

my $session; 
$queryUniques->bind_columns(\$session); 

my $counter = 1; 
my $sessionString; 
while(my $hashref = $queryUniques->fetch()) { 
print "Fetching Row\n"; 
if($counter == 1) { 
    $sessionString = "'" . $session . "'"; 
} else { 
    $sessionString = $sessionString . ", '" . $session . "'"; 
} 
$counter++; 
} 
if ($queryUniques->err()) { 
print "ERROR = " . $queryUniques->errstr . "\n"; 
} 

print "$sessionString\n"; 

je essentiellement pris la deuxième requête et fixé quelques petites choses ici et là. La dernière ligne affiche le $sessionString qui est une liste de toutes vos sessions séparées par des guillemets. Cette partie a fonctionné.

La deuxième partie est l'endroit où les choses deviennent étranges. Vous prenez $sessionString et le transmettez comme une instruction SQL. À moins qu'il y ait quelque chose que je ne vois pas, $sessionString est simplement une liste de sessions et non une instruction SQL en elle-même. Comme je l'ai dit, vérifiez les erreurs avec chaque appel DBI, et voyez si vous faites une erreur quelque part.

Vous pouvez également ajouter une ligne comme celle-ci:

print qq(DEBUG: SQL Query = '$sqlStatement'\n); 

avant d'exécuter un $sth->prepare($sqlStatement) et de cette façon, vous pouvez voir ce que votre instruction SQL est.


Le problème

On dirait que vous préparez la deuxième requête avant de comprendre ce que (?) devrait être (que je suppose est votre groupe de sessionString $).

Vous devez remplacer les sessions par (?)AVANT de vous devez faire votre DBI-> prepare().

Quelque chose comme ça (pas testé):

(my $sessionQuery = $query) =~ s/\(\?\)/$sessionString/; 
my $querySth = $connect->prepare($sessionQuery); 
$querySth->execute(); 
my @test = $queryPrep->fetchall_arrayref(); 

Rappelez-vous que la syntaxe qq() citant est votre ami. J'utilise ce lot:

print qq(DEBUG: \$foo = "$foo"\n); 

Et parfois, je simplement copier et coller une déclaration puis citer:

print qq(DEBUG: while (my $foo = foobar($bar)) };\n); 

Il est incroyable de voir combien d'erreurs que je peux attraper cette façon. Je peux alors chercher DEBUG: dans mon programme et supprimer ces lignes.

Rappelez-vous d'écrire vos programmes un peu à la fois, voir si vous pouvez obtenir $sessionString de travail. Ensuite, essayez de voir si vous pouvez le remplacer dans votre $query, puis essayez d'exécuter la requête calculée.

Perl est un langage agréable et puissant, mais la syntaxe peut parfois être un peu croustillante - surtout si vous n'êtes pas habitué à Perl orienté objet.

+0

"chaque fois que vous faites un appel DBI, vous devriez faire ceci: if ($ sth-> err())" est si moche. Vous pouvez simplement définir RaiseError => 1 dans l'appel de la méthode connect et toute méthode qui échoue va mourir. – bohica

+0

@bohica Oui, au cours des trois dernières années, j'ai changé mes méthodes de programmation en programmation basée sur les exceptions. Quand j'écris des modules, ils coassent simplement et ne renvoient plus undefs si quelque chose ne va pas. Si vous n'aimez pas cela, enveloppez l'appel dans un 'eval'. J'utilise maintenant 'use autodie;' dans tous mes programmes. Cependant, le point principal est que vous ne devriez pas aveuglément faire confiance à ce que vous obtenez des appels de module. S'ils sont basés sur une exception, enveloppez-les dans un eval, de sorte que vous pouvez gérer l'exception si vous voulez gérer l'erreur avec élégance. –

0

Juste deux questions à vous poser:

1) Quelle est la valeur de $sessionString juste avant l'appel à execute()?

2) Quelle est la valeur de retour de la méthode execute?
Essayez:

$queryPrep->execute($sessionString) or die $queryPrep->errstr; 
-1

Où $ prochaine session de ?? D'abord et avant tout, je suggère de mettre

use strict; 

dans vos programmes perl afin que vous pouvez attraper de nombreux bugs faciles avant qu'ils ne surviennent.

On dirait que le nœud du problème est votre tentative de construction de chaînes entre guillemets séparés par des virgules. Dans ce cas, j'utiliserais un tableau pour stocker les valeurs dont vous avez besoin, puis je les joindrais à avant que émette la requête. Par exemple:

my @sessions =(); 

# perhaps you meant this? 
while(my $session = $queryUniques->fetch()) { 
    push @sessions, $session 

    if((scalar @sessions) % 5 == 0) { 
     my $sessionString = join ",", map { "'$_'" } @sessions; 
     @sessions =(); 
     $queryPrep->execute($sessionString); 
     my @test = $queryPrep->fetchall_arrayref(); 
    } 
} 
+2

Ne faites pas cela, ce n'est pas [Bobby Tables] (http://xkcd.com/327/) sûr (si cela fonctionne, même, ce qui semble peu probable). Jetez un oeil à [ce lien] (http://search.cpan.org/perldoc/DBI#Placeholders_and_Bind_Values), à partir de la réponse de Chip/Sinan. – mscha

+0

oui, j'aborderais l'objectif différemment - peut-être que vous pouvez élaborer dans votre propre réponse. – jbremnant

Questions connexes