Conteggio delle righe con DOP


192

Ci sono molte dichiarazioni contrastanti in giro. Qual è il modo migliore per contare le righe usando DOP in PHP? Prima di usare il DOP, ho semplicemente usato mysql_num_rows.

fetchAll è qualcosa che non vorrò perché a volte potrei avere a che fare con set di dati di grandi dimensioni, quindi non va bene per il mio uso.

Hai qualche suggerimento?

Risposte:


265
$sql = "SELECT count(*) FROM `table` WHERE foo = ?"; 
$result = $con->prepare($sql); 
$result->execute([$bar]); 
$number_of_rows = $result->fetchColumn(); 

Non è il modo più elegante per farlo, inoltre comporta una query aggiuntiva.

DOP ha PDOStatement::rowCount(), che apparentemente non funziona in MySql. Che dolore.

Dal documento DOP:

Per la maggior parte dei database, PDOStatement :: rowCount () non restituisce il numero di righe interessate da un'istruzione SELECT. Utilizzare invece PDO :: query () per emettere un'istruzione SELECT COUNT (*) con gli stessi predicati dell'istruzione SELECT desiderata, quindi utilizzare PDOStatement :: fetchColumn () per recuperare il numero di righe che verranno restituite. L'applicazione può quindi eseguire l'azione corretta.

EDIT: L'esempio di codice sopra riportato utilizza un'istruzione preparata, che in molti casi è probabilmente non necessaria ai fini del conteggio delle righe, quindi:

$nRows = $pdo->query('select count(*) from blah')->fetchColumn(); 
echo $nRows;

questo significherebbe fare una query aggiuntiva sul database. Presumo che abbia già fatto una query selezionata e ora voglia sapere quante righe sono state restituite.
nickf

1
il nickf è corretto. mysql_num_rows () non funzionerà quando si utilizza PDO, però?
James,

È vero, apparentemente c'è PDOStatement :: rowCount () ma non funziona in MySql
karim79,

11
Usando questo approccio, fetchColumn()restituisce una stringa "1234" ... il tuo EDIT ha echo count($nRows);- count()è una funzione di matrice: P. Consiglierei anche di digitare il cast del risultato fetchColumn()in un numero intero. $count = (int) $stmt->fetchColumn()
Cobby,

1
@ karim79 L'approccio dell'istruzione non preparata restituisce solo 1 anziché il numero effettivo di righe. La dichiarazione preparata funziona bene. Quale può essere il problema?
SilentAssassin,

86

Come ho scritto in precedenza in una risposta a una domanda simile , l'unica ragione ha mysql_num_rows()funzionato è perché stava recuperando internamente tutte le righe per darti quell'informazione, anche se non ti sembrava.

Quindi in DOP, le tue opzioni sono:

  1. Usa la FOUND_ROWS()funzione di MySQL .
  2. Utilizzare la fetchAll()funzione PDO per recuperare tutte le righe in un array, quindi utilizzarlo count().
  3. Fai una query extra SELECT COUNT(*), come suggerito da karim79.

8
Grazie per avermi istruito ulteriormente su mysql_num_rows () sembra che potrebbe essere un collo di bottiglia importante che mi stavo dando. Grazie ancora.
James,

2
fetch_all in realtà è fetchAll () :)
dinamico

2
L'opzione 2 non è consigliabile se il risultato è grande.
Edson Horacio Junior,

FOUND_ROWS () verrà rimosso da MySQL, quindi controlla il link a FOUND_ROWS prima di utilizzarlo se ne hai già familiarità.
Anatak,

29

Come spesso accade, questa domanda è confusa da morire. Le persone vengono qui con in mente due diversi compiti :

  1. Devono sapere quante righe nella tabella
  2. Devono sapere se una query ha restituito delle righe

Sono due compiti assolutamente diversi che non hanno nulla in comune e non possono essere risolti con la stessa funzione. Ironia della sorte, per nessuno dei duePDOStatement::rowCount() deve essere utilizzata la funzione effettiva .

Vediamo perché

Conteggio delle righe nella tabella

Prima di usare DOP ho semplicemente usato mysql_num_rows().

Significa che hai già fatto male. L'utilizzo mysql_num_rows()o il rowCount()conteggio del numero di righe nella tabella è un vero disastro in termini di consumo delle risorse del server. Un database deve leggere tutte le righe dal disco, consumare la memoria sul server di database, quindi inviare tutto questo mucchio di dati a PHP, consumando anche la memoria del processo PHP, caricando il server senza motivo.
Inoltre, selezionare le righe solo per contarle semplicemente non ha senso. È count(*)invece necessario eseguire una query. Il database conteggerà i record dall'indice, senza leggere le righe effettive e quindi verrà restituita solo una riga.

A tal fine, il codice suggerito nella risposta accettata è equo.

Contando le righe numeriche restituite.

Il secondo caso d'uso non è così disastroso quanto piuttosto inutile: nel caso tu abbia bisogno di sapere se la tua query ha restituito dei dati, hai sempre i dati stessi!

Ad esempio, se stai selezionando solo una riga. Va bene, puoi usare la riga recuperata come flag:

$stmt->execute();
$row = $stmt->fetch();
if (!$row) { // here! as simple as that
    echo 'No data found';
}

Nel caso in cui sia necessario ottenere più righe, è possibile utilizzare fetchAll().

fetchAll() è qualcosa che non vorrò perché a volte potrei avere a che fare con set di dati di grandi dimensioni

Sì, certo, per il primo caso d'uso sarebbe due volte più cattivo. Ma come abbiamo già appreso, non selezionare le righe solo per contarle, né con rowCount()fetchAll().

Ma nel caso in cui utilizzerai effettivamente le righe selezionate, non c'è nulla di sbagliato nell'uso fetchAll(). Ricorda che in un'applicazione web non dovresti mai selezionare un numero enorme di righe. Solo le righe che saranno effettivamente utilizzati in una pagina web dovrebbero essere selezionati, quindi hai avuto modo di uso LIMIT, WHEREo di una clausola simile nel vostro SQL. E per una quantità così moderata di dati è tutto a posto fetchAll(). E ancora, basta usare il risultato di questa funzione nella condizione:

$stmt->execute();
$data = $stmt->fetchAll();
if (!$data) { // again, no rowCount() is needed!
    echo 'No data found';
}

E naturalmente sarà una follia assoluta eseguire una query aggiuntiva solo per dire se l'altra query ha restituito delle righe, come suggerito nelle due risposte principali.

Contando il numero di righe in un set di risultati di grandi dimensioni

In un caso così raro quando è necessario selezionare una quantità enorme di righe (ad esempio in un'applicazione console), è necessario utilizzare una query senza buffer , al fine di ridurre la quantità di memoria utilizzata. Ma questo è il caso reale quando rowCount() non sarà disponibile , quindi non è utile anche per questa funzione.

Quindi, questo è l'unico caso d'uso in cui potrebbe essere necessario eseguire una query aggiuntiva, nel caso in cui sia necessario conoscere una stima ravvicinata del numero di righe selezionate.


è utile se l'API deve stampare i risultati totali di una query di ricerca. ti restituirà solo 10 o 15 righe, ma dovrebbe anche dirti che ci sono 284 risultati totali.
Andres SK,

4
@andufo Non lo è. Ricorda: uno sviluppatore non dovrebbe mai farlo in questo modo. La query di ricerca non dovrebbe mai restituire tutte le 284 righe. 15 devono essere restituiti per mostrare e una riga da una query separata per indicare che sono stati trovati 284.
Il tuo senso comune

2
Questo è un ottimo punto - all'inizio non intuitivo, ma valido. Molte persone dimenticano che due semplici query SQL sono molto più veloci di una leggermente più grande. Per giustificare qualsiasi conteggio, dovresti avere una query molto lenta che non può essere ottimizzata e produrrà probabilmente pochi risultati. Grazie per la segnalazione!
PeerBr

@Il tuo buon senso: ne sono sicuro: fetchAll () non sarà una cattiva idea se il set di risultati è molto grande? Non sarebbe meglio quindi usare fetch () per ottenere i dati successivamente.
timmorn Sì

@timmornYE questo è esattamente ciò che viene detto nell'ultimo paragrafo della mia risposta
Il tuo senso comune

21

È molto tardi, ma ho riscontrato un problema e lo faccio:

function countAll($table){
   $dbh = dbConnect();
   $sql = "select * from `$table`";

   $stmt = $dbh->prepare($sql);
    try { $stmt->execute();}
    catch(PDOException $e){echo $e->getMessage();}

return $stmt->rowCount();

È davvero semplice e facile. :)


19
Selezionare tutti i dati solo per contarli, è contro le regole più basilari dell'interazione con il database.
Il tuo senso comune

Forse vuoi avere una barra di avanzamento per tutti i valori restituiti, quindi devi conoscere il numero di righe in anticipo.
Jonny il

18

Ho finito per usare questo:

$result = $db->query($query)->fetchAll();

if (count($result) > 0) {
    foreach ($result as $row) {
        echo $row['blah'] . '<br />';
    }
} else {
    echo "<p>Nothing matched your query.</p>";
}

12

Questo post è vecchio ma Ottenere il conteggio delle righe in php con DOP è semplice

$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();

3
Vedi la documentazione citata nella risposta di karim79. Questo a volte funziona ma non è affidabile.
octern

5

Questo è un vecchio post, ma frustrato in cerca di alternative. È davvero un peccato che il PDO non abbia questa caratteristica, specialmente perché PHP e MySQL tendono ad andare di pari passo.

Vi è uno sfortunato difetto nell'uso di fetchColumn () poiché non è più possibile utilizzare tale set di risultati (in modo efficace) poiché fetchColumn () sposta l'ago sulla riga successiva. Ad esempio, se hai un risultato simile a

  1. Frutta-> Banana
  2. Frutta-> Mela
  3. Frutta-> Orange

Se usi fetchColumn () puoi scoprire che ci sono 3 frutti restituiti, ma se ora esegui il ciclo attraverso il risultato, hai solo due colonne, Il prezzo di fetchColumn () è la perdita della prima colonna di risultati solo per trovare quante righe sono state restituite. Ciò porta a una codifica sciatta e risultati totalmente errati se implementati.

Quindi ora, usando fetchColumn () devi implementare una nuova chiamata e una query MySQL solo per ottenere un nuovo set di risultati funzionanti. (che si spera non sia cambiato dall'ultima query), lo so, è improbabile, ma può succedere. Inoltre, l'overhead delle doppie query su tutte le convalide conta le convalide. Che per questo esempio è piccolo, ma analizza 2 milioni di righe su una query unita, non un prezzo piacevole da pagare.

Adoro PHP e supporto chiunque sia coinvolto nel suo sviluppo, così come la comunità in generale, usando PHP quotidianamente, ma spero davvero che questo sia affrontato nelle versioni future. Questa è "davvero" la mia unica lamentela con PHP DOP, che altrimenti è una grande classe.


2

Rispondendo a questo perché mi sono intrappolato ormai sapendo questo e forse sarà utile.

Tieni presente che non puoi recuperare i risultati due volte. Devi salvare il risultato del recupero nell'array, ottenere il conteggio delle righe count($array)e generare i risultati con foreach. Per esempio:

$query = "your_query_here";
$STH = $DBH->prepare($query);
$STH->execute();
$rows = $STH->fetchAll();
//all your results is in $rows array
$STH->setFetchMode(PDO::FETCH_ASSOC);           
if (count($rows) > 0) {             
    foreach ($rows as $row) {
        //output your rows
    }                       
}

1

Se vuoi solo ottenere un conteggio di righe (non i dati), ad es. usando COUNT (*) in un'istruzione preparata, tutto ciò che devi fare è recuperare il risultato e leggere il valore:

$sql = "SELECT count(*) FROM `table` WHERE foo = bar";
$statement = $con->prepare($sql); 
$statement->execute(); 
$count = $statement->fetch(PDO::FETCH_NUM); // Return array indexed by column number
return reset($count); // Resets array cursor and returns first value (the count)

Il recupero effettivo di tutte le righe (dati) per eseguire un conteggio semplice è uno spreco di risorse. Se il set di risultati è grande, il server potrebbe soffocarlo.



1

Per usare le variabili all'interno di una query devi usare bindValue()o bindParam(). E non concatenare le variabili con" . $variable . "

$statement = "SELECT count(account_id) FROM account
                  WHERE email = ? AND is_email_confirmed;";
$preparedStatement = $this->postgreSqlHandler->prepare($statement);
$preparedStatement->bindValue(1, $account->getEmail());
$preparedStatement->execute();
$numberRows= $preparedStatement->fetchColumn();

GL


0

Quando si tratta di mysql come contare o ottenere quante righe in una tabella con PHP DOP lo uso

// count total number of rows
$query = "SELECT COUNT(*) as total_rows FROM sometable";
$stmt = $con->prepare($query);

// execute query
$stmt->execute();

// get total rows
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$total_rows = $row['total_rows'];

i crediti vanno a Mike @ codeofaninja.com


-1

Una breve riga per ottenere la prima voce restituita. Questo è utile per domande di base.

<?php
$count = current($db->query("select count(*) from table")->fetch());
?>

Riferimento


-1

Ho provato $count = $stmt->rowCount();con Oracle 11.2 e non ha funzionato. Ho deciso di utilizzare un ciclo for come mostrato di seguito.

   $count =  "";
    $stmt =  $conn->prepare($sql);
    $stmt->execute();
   echo "<table border='1'>\n";
   while($row = $stmt->fetch(PDO::FETCH_OBJ)) {
        $count++;
        echo "<tr>\n";
    foreach ($row as $item) {
    echo "<td class='td2'>".($item !== null ? htmlentities($item, ENT_QUOTES):"&nbsp;")."</td>\n";
        } //foreach ends
        }// while ends
        echo "</table>\n";
       //echo " no of rows : ". oci_num_rows($stmt);
       //equivalent in pdo::prepare statement
       echo "no.of rows :".$count;

-1

Per domande dirette in cui desidero una riga specifica e voglio sapere se è stata trovata, utilizzo qualcosa del tipo:

function fetchSpecificRow(&$myRecord) {
    $myRecord = array();
    $myQuery = "some sql...";
    $stmt = $this->prepare($myQuery);
    $stmt->execute(array($parm1, $parm2, ...));
    if ($myRecord = $stmt->fetch(PDO::FETCH_ASSOC)) return 0;
    return $myErrNum;
}

-1

C'è una soluzione semplice. Se usi PDO Connetti al tuo DB in questo modo:

try {
    $handler = new PDO('mysql:host=localhost;dbname=name_of_your_db', 'your_login', 'your_password'); 
    $handler -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} 
    catch (PDOException $e) {   
    echo $e->getMessage();
}

Quindi, la query su DB sarà:

$query = $handler->query("SELECT id FROM your_table WHERE ...");

E infine, per contare le righe corrispondenti alla tua query scrivi in ​​questo modo

$amountOfRows = $query->rowcount();

Perché questo mi restituisce -1 per la maggior parte del tempo? Anche se ci sono dati. .
Ingus

-1

fetchColumn ()

utilizzato se si desidera ottenere il conteggio dei record [effisien]

$sql   = "SELECT COUNT(*) FROM fruit WHERE calories > 100";
$res   = $conn->query($sql);
$count = $res->fetchColumn(); // ex = 2

query ()

usato se si desidera recuperare i dati e contare il record [opzioni]

$sql = "SELECT * FROM fruit WHERE calories > 100";
$res = $conn->query($sql);

if ( $res->rowCount() > 0) {

    foreach ( $res as $row ) {
        print "Name: {$row['NAME']} <br />";
    }

}
else {
    print "No rows matched the query.";
}

PDOStatement :: rowCount


Non dovresti mai farlo. Su un tavolo più o meno grande consumerà tutta la memoria del server e causerà l'arresto anomalo del server
Il tuo senso comune

Ora la tua risposta duplica solo una dozzina di risposte esistenti.
Il tuo buon senso

-2

quando crei un COUNT (*) nella tua dichiarazione mysql come in

$q = $db->query("SELECT COUNT(*) FROM ...");

la tua query mysql sta già contando il numero di risultati perché contare di nuovo in php? per ottenere il risultato del tuo mysql

$q = $db->query("SELECT COUNT(*) as counted FROM ...");
$nb = $q->fetch(PDO::FETCH_OBJ);
$nb = $nb->counted;

e $nbconterrà il numero intero che hai contato con la tua istruzione mysql un po 'lungo da scrivere ma veloce da eseguire

Modifica: scusate il post sbagliato ma come alcuni esempi mostrano query con conteggio in, stavo suggerendo di usare il risultato mysql, ma se non usate il conteggio in sql fetchAll () è efficace, se salvate il risultato in una variabile non perderai una linea.

$data = $dbh->query("SELECT * FROM ...");
$table = $data->fetchAll(PDO::FETCH_OBJ);

count($table)restituirà il numero di righe e puoi comunque utilizzare il risultato dopo averlo $row = $table[0] usato o usando aforeach

foreach($table as $row){
  print $row->id;
}

1
La domanda è: come contare quando NON fai un CONTE (*) nella tua dichiarazione mysql
Il tuo senso comune

-2

Ecco un'estensione su misura della classe PDO, con una funzione di aiuto per recuperare il numero di righe incluse dai criteri "WHERE" dell'ultima query.

Potrebbe essere necessario aggiungere altri "gestori", tuttavia, a seconda dei comandi utilizzati. In questo momento funziona solo per le query che utilizzano "FROM" o "UPDATE".

class PDO_V extends PDO
{
    private $lastQuery = null;

    public function query($query)
    {
        $this->lastQuery = $query;    
        return parent::query($query);
    }
    public function getLastQueryRowCount()
    {
        $lastQuery = $this->lastQuery;
        $commandBeforeTableName = null;
        if (strpos($lastQuery, 'FROM') !== false)
            $commandBeforeTableName = 'FROM';
        if (strpos($lastQuery, 'UPDATE') !== false)
            $commandBeforeTableName = 'UPDATE';

        $after = substr($lastQuery, strpos($lastQuery, $commandBeforeTableName) + (strlen($commandBeforeTableName) + 1));
        $table = substr($after, 0, strpos($after, ' '));

        $wherePart = substr($lastQuery, strpos($lastQuery, 'WHERE'));

        $result = parent::query("SELECT COUNT(*) FROM $table " . $wherePart);
        if ($result == null)
            return 0;
        return $result->fetchColumn();
    }
}

Il problema non merita uno sforzo. Tale numero è necessario così raramente che non è necessaria un'estensione dedicata. Per non parlare del fatto che non supporta le dichiarazioni preparate, l'unica ragione per usare DOP.
Il tuo buon senso,

-2

Puoi combinare il metodo migliore in una riga o funzione e avere la nuova query generata automaticamente per te:

function getRowCount($q){ 
    global $db;
    return $db->query(preg_replace('/SELECT [A-Za-z,]+ FROM /i','SELECT count(*) FROM ',$q))->fetchColumn();
}

$numRows = getRowCount($query);

Niente di meglio in questo metodo. Eseguire una query aggiuntiva solo per sapere quante righe sono state restituite non ha assolutamente senso.
Il tuo buon senso,

-2
<table>
      <thead>
           <tr>
                <th>Sn.</th>
                <th>Name</th>
           </tr>
      </thead>
      <tbody>
<?php
     $i=0;
     $statement = $db->prepare("SELECT * FROM tbl_user ORDER BY name ASC");
     $statement->execute();
     $result = $statement->fetchColumn();
     foreach($result as $row) {
        $i++;
    ?>  
      <tr>
         <td><?php echo $i; ?></td>
         <td><?php echo $row['name']; ?></td>
      </tr>
     <?php
          }
     ?>
     </tbody>
</table>

1
Questa è davvero una cattiva idea. Selezionando tutte le righe, è un enorme spreco di larghezza di banda.
Nafees,

-2
function count_x($connect) {  
 $query = "  SELECT * FROM tbl WHERE id = '0' ";  
 $statement = $connect->prepare($query);  $statement->execute();  
 $total_rows = $statement->rowCount();  
 return $total_rows; 
}

-4

Usa il parametro array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL), altrimenti mostra -1:

Usen parametro array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL), sin ello sale -1

esempio:

$res1 = $mdb2->prepare("SELECT clave FROM $tb WHERE id_usuario='$username' AND activo=1 and id_tipo_usuario='4'", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$res1->execute();

$count=$res1->rowCount();
echo $count;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.