2009-05-12 4 views

Répondre

9

Afin de savoir combien de lignes sont dans un jeu de résultats que vous avez exactement deux options:

  1. select count(*)
  2. itérer sur le jeu de résultats et compte les lignes.

Vous pouvez introduire de la magie via une procédure stockée qui renvoie un tableau ou quelque chose de plus sophistiqué, mais finalement l'une de ces deux choses doit se produire. Donc, il n'y a pas de moyen de fancypants pour obtenir ce résultat. Vous avez juste à les compter :-)

+1

La clé ici était mon incompréhension de ce que fetch fait. Je pensais qu'il récupérait une sorte de hachage et que je l'itéra simplement, mais, en fait, le tout est un flux, alors, vous récupérez des lignes directement à partir de la BD (et non d'un objet retourné), donc, l'exécution préparée n'a vraiment aucune idée du nombre de lignes renvoyées. –

17

Basé sur un coup d'œil here, il semble que après avoir exécuté

$statement->execute($arg) 

vous pouvez accéder à la ligne compte via

$statement->rows 
+0

qui est vraiment gênant ... c'est exactement là où je cherchais, mais totalement raté parce qu'ils ont mis que si ($ sth-> lignes == 0) APRÈS la boucle où ils lisent les lignes !! merci de l'avoir attrapé. –

+3

Notez la mise en garde très importante concernant les lignes dans le [http://search.cpan.org/~timb/DBI-1.608/DBI.pm#rows POD]. – jplindstrom

+0

Euh, ouais, ce n'est pas comme ça que vous faites apparemment des liens :) – jplindstrom

0

Les lignes ne certainement varier en fonction de la base de données/version du pilote, il semble. Je regarderais certainement à un morceau de logique là qui a traité des résultats inattendus.

11

Le "caveat" in the documentation (lié à un commentaire sur une autre réponse) est importante, et fournit le vrai, la réponse correcte:

En général, vous ne pouvez compter sur une ligne compte après une non -SELECT execute (pour certaines opérations spécifiques comme UPDATE et DELETE), ou après avoir récupéré toutes les lignes d'une instruction SELECT.

Pour les instructions SELECT, il n'est généralement pas possible de connaître le nombre de lignes renvoyées, sauf en les récupérant toutes. Certains pilotes renvoient le nombre de lignes que l'application a déjà récupérées, mais d'autres peuvent renvoyer -1 jusqu'à ce que toutes les lignes aient été récupérées. L'utilisation de la méthode rows ou $ DBI :: rows avec les instructions SELECT n'est donc pas recommandée.

+3

donc, maintenant que nous savons que -> lignes n'est pas la réponse à la question ... quelle est la réponse? Dans l'exemple cité ci-dessus (dans la réponse que j'ai d'abord choisie comme correcte), ils font une sélection puis voient si les lignes == 0 ... alors, je suis de nouveau confus. –

+0

Comme le disent les docs, "Pour les instructions SELECT, il n'est généralement pas possible de savoir combien de lignes seront renvoyées sauf en les récupérant toutes." Le mot clé est "généralement". Certaines bases de données utilisant certains moteurs peuvent se comporter différemment. Mais la seule façon d'être sûr à 100% dans tous les cas possibles est d'aller chercher chaque ligne et de compter. –

2

Essayez cette solution SQL, combinez votre SQL pour les données avec une déclaration de compte.

 
select null, null, null, count(*) from tablex 
union 
select foo, bar, foobar, null from tablex 

la première instruction aura le nombre, et devrait être la première ligne (sinon vous pouvez commander par la contourner) le cycle, alors vous pouvez le reste du jeu d'enregistrements à votre guise.

1

J'ai dynamiquement généré un SQL et l'ai exécuté. Pour moi select count(*) ne semble pas être une option parce que je dois re-générer la requête à nouveau. L'approche suivante a semblé propre pour moi. Mais vous devez à nouveau émettre s $h->execute() pour récupérer les données de ligne.

$h->execute() or die "ERROR: Couldn't execute SQL statement"; 
$rowcount_ref = $h->fetchall_arrayref(0); 
$rowcount = scalar (@{$rowcount_ref}); 

- Shaakunthala

4

Il est un peu en retard, mais si quelqu'un utilise ORACLE, vient ici la solution de sueur:

SELECT 
    q.*, 
    ROWNUM DB_ROWNUM, 
    (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT 
FROM 
    ($sql) q 

$ sql est votre requête, bien sûr. Oracles optimiseur est assez intelligent pour ne pas tout exécuter deux fois.

Maintenant, chaque ligne récupérée contient le numéro de ligne actuel (utile pour la numérotation des lignes de la grille de pagination) dans DB_ROWNUM et le nombre total de lignes dans DB_COUNT. Vous devez toujours chercher au moins une ligne (donc ce n'est pas exactement la réponse à la question ci-dessus;)), mais l'utilisation de sueur vient ensuite:

C'est aussi un moyen très facile de démarrer et de limiter dans Oracle et toujours obtenir le nombre total de lignes:

SELECT * FROM (
    SELECT /*+ FIRST_ROWS($limit) */ 
    q.*, 
    ROWNUM DB_ROWNUM, 
    (SELECT max(ROWNUM) FROM ($sql)) DB_COUNT 
    FROM 
    ($sql) q 
    WHERE 
    ROWNUM <= $limit 
) 
WHERE 
    DB_ROWNUM > $start 

Avec cela, vous pouvez réellement chercher uniquement la ligne 51 à 100 pour la deuxième page dans votre réseau, mais toujours le nombre réel de ligne (à partir de 1) et la compte complet (sans début et limite) dans chaque ligne récupérée.

+4

voulez-vous dire sueur ou douce? –

2

CPAN dit:

[...] ou après l'extraction de toutes les lignes d'une instruction SELECT.

donc faire quelque chose comme cela va probablement travailler:

$sth->execute() or die $sth->errstr(); 
my $hasref = $sth->fetchall_hashref('id'); 
say "There is/are " . scalar(keys(%{$hasref}) . " row(s)."; 
0

Si vous voulez savoir combien de lignes sont là, avant de marcher à travers tous, une solution spécifique à MySQL pourrait être FOUND_ROWS(). Dans votre première requête, ajoutez SQL_CALC_FOUND_ROWS juste après SELECT. Ensuite, faites SELECT FOUND_ROWS();, et vous avez accès au nombre de lignes tout de suite. Vous pouvez maintenant décider si vous voulez parcourir toutes les lignes ou la meilleure façon de le faire.

Notez qu'ayant LIMIT dans la requête vous donnera le nombre total de requêtes aurait retourné sans LIMIT.

0

Comme d'autres l'ont déjà dit, vous avez vraiment besoin d'obtenir les lignes pour savoir s'il y en a. Si vous avez besoin de savoir avant de commencer une boucle sur chaque ligne, et si les résultats attendus ne sont pas énormes, vous pouvez obtenir tous les résultats dans un tableau, puis vérifier cela.

J'ai récemment utilisé quelque chose comme ça:

foreach my $table (qw(ACTOR DIRECTOR PRODUCER WRITER)) { 
    my $sth = $dbi->prepare(qq{SELECT * FROM $table WHERE DESCRIPTION != TRIM(DESCRIPTION)}) 
     or die $dbi->errstr; 
    $sth->execute or die $sth->errstr; 

    my @rows = @{ $sth->fetchall_arrayref() }; 

    next unless @rows; 

    foreach my $row (@rows) { 
     print join(", ", map {qq("$_")} @{$row}), "\n"; 
    } 
} 
Questions connexes