Recuento de filas con DOP

192

Hay muchas declaraciones en conflicto alrededor. ¿Cuál es la mejor manera de contar filas usando PDO en PHP? Antes de usar PDO, simplemente usémysql_num_rows .

fetchAll es algo que no querré porque a veces puedo estar tratando con grandes conjuntos de datos, por lo que no es bueno para mi uso.

¿Tienes alguna sugerencia?

James
fuente

Respuestas:

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

No es la forma más elegante de hacerlo, además implica una consulta adicional.

DOP tiene PDOStatement::rowCount(), que aparentemente no funciona en MySql. Que dolor.

Desde el documento PDO:

Para la mayoría de las bases de datos, PDOStatement :: rowCount () no devuelve el número de filas afectadas por una instrucción SELECT. En su lugar, use PDO :: query () para emitir una declaración SELECT COUNT (*) con los mismos predicados que su declaración SELECT deseada, luego use PDOStatement :: fetchColumn () para recuperar el número de filas que se devolverán. Su aplicación puede realizar la acción correcta.

EDITAR: El ejemplo de código anterior usa una declaración preparada, que en muchos casos probablemente no sea necesaria para contar filas, por lo tanto:

$nRows = $pdo->query('select count(*) from blah')->fetchColumn(); 
echo $nRows;
karim79
fuente
Esto significaría hacer una consulta adicional a la base de datos. Supongo que ya ha hecho una consulta de selección y ahora quiere saber cuántas filas se devolvieron.
nickf
1
Nickf es correcto. mysql_num_rows () no funcionará cuando use PDO, ¿no?
James
Es cierto, aparentemente hay PDOStatement :: rowCount () pero eso no funciona en
MySql
11
Usando este enfoque, fetchColumn()devuelve una cadena "1234" ... su EDIT tiene echo count($nRows);- count()es una función de matriz: P. También recomendaría escribir el resultado desde fetchColumn()un entero. $count = (int) $stmt->fetchColumn()
Cobby
1
@ karim79 El enfoque de declaración no preparada devuelve 1 solo en lugar del número real de filas. La declaración preparada funciona bien. Cuál puede ser el problema ?
SilentAssassin
86

Como escribí anteriormente en una respuesta a una pregunta similar , la única razónmysql_num_rows() funcionó es porque estaba recuperando internamente todas las filas para brindarle esa información, incluso si no le parecía.

Entonces, en PDO, sus opciones son:

  1. Utiliza la FOUND_ROWS()función de MySQL .
  2. Use la fetchAll()función PDO para buscar todas las filas en una matriz, luego úsela count().
  3. Haga una consulta adicional a SELECT COUNT(*), como sugirió karim79.
Abedul Chad
fuente
8
Gracias por educarme más sobre mysql_num_rows () parece que puede ser un cuello de botella importante que me estaba dando. Gracias de nuevo.
James
2
fetch_all en realidad es fetchAll () :)
dinámico
2
La opción 2 no es recomendable si el resultado es grande.
Edson Horacio Junior
FOUND_ROWS () se eliminará de MySQL, por lo tanto, compruebe el enlace a FOUND_ROWS antes de usar esto si ya estaba familiarizado con esto.
anatak
28

Como suele suceder, esta pregunta es confusa como el infierno. La gente viene aquí con dos tareas diferentes en mente:

  1. Necesitan saber cuántas filas hay en la tabla.
  2. Necesitan saber si una consulta devolvió alguna fila

Son dos tareas absolutamente diferentes que no tienen nada en común y que no pueden resolverse con la misma función. Irónicamente, para ninguno de ellosPDOStatement::rowCount() se debe usar la función real .

Veamos porque

Contando filas en la tabla

Antes de usar PDO simplemente lo usé mysql_num_rows().

Significa que ya lo hiciste mal. Usar mysql_num_rows()o rowCount()contar el número de filas en la tabla es un verdadero desastre en términos de consumo de los recursos del servidor. Una base de datos tiene que leer todas las filas del disco, consumir la memoria en el servidor de la base de datos, luego enviar todo este montón de datos a PHP, consumiendo también la memoria del proceso de PHP, cargando su servidor sin ninguna razón.
Además, seleccionar filas solo para contarlas simplemente no tiene sentido. En su lugar, count(*)se debe ejecutar una consulta. La base de datos contará los registros del índice, sin leer las filas reales y luego solo se devolverá una fila.

Para este propósito, el código sugerido en la respuesta aceptada es justo.

Contando el número de filas devueltas.

El segundo caso de uso no es tan desastroso como bastante inútil: en caso de que necesite saber si su consulta devolvió algún dato, ¡siempre tiene los datos en sí!

Diga, si está seleccionando solo una fila. Muy bien, puedes usar la fila obtenida como una bandera:

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

En caso de que necesite obtener muchas filas, puede usar fetchAll().

fetchAll() es algo que no querré, ya que a veces estoy tratando con grandes conjuntos de datos

Sí, por supuesto, para el primer caso de uso sería el doble de malo. Pero como ya aprendimos, simplemente no seleccione las filas solo para contarlas, ni con rowCount()ni fetchAll().

Pero en caso de que realmente vaya a usar las filas seleccionadas, no hay nada de malo en usarlas fetchAll(). Recuerde que en una aplicación web nunca debe seleccionar una gran cantidad de filas. Sólo las filas que se utilizan realmente en una página web deben ser seleccionados, por lo tanto, usted tiene que usar LIMIT, WHEREo una cláusula similar en su SQL. Y para una cantidad tan moderada de datos está bien usarlo fetchAll(). Y nuevamente, solo use el resultado de esta función en la condición:

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

Y, por supuesto, será una locura absoluta ejecutar una consulta adicional solo para saber si su otra consulta devolvió alguna fila, como se sugiere en las dos respuestas principales.

Contando el número de filas en un conjunto de resultados grande

En un caso tan raro cuando necesita seleccionar una gran cantidad real de filas (en una aplicación de consola, por ejemplo), debe usar una consulta sin búfer para reducir la cantidad de memoria utilizada. Pero este es el caso real cuando rowCount() no estará disponible , por lo tanto, no hay uso para esta función también.

Por lo tanto, ese es el único caso de uso cuando posiblemente necesite ejecutar una consulta adicional, en caso de que necesite conocer una estimación cercana para el número de filas seleccionadas.

Su sentido común
fuente
es útil si la API necesita imprimir los resultados totales de una consulta de búsqueda. solo le devolverá 10 o 15 filas, pero también debería decirle que hay 284 resultados totales.
Andres SK
44
@andufo no lo es. Recuerde: un desarrollador nunca debería hacerlo de esta manera. La consulta de búsqueda nunca debe devolver las 284 filas. 15 deben devolverse para mostrar y una fila de una consulta separada para indicar que se encontraron 284.
Su sentido común
2
Este es un muy buen punto: poco intuitivo al principio, pero válido. La mayoría de la gente olvida que dos consultas SQL simples son mucho más rápidas que una ligeramente más grande. Para justificar cualquier recuento, debe tener una consulta muy lenta que no se pueda optimizar y que probablemente produzca pocos resultados. ¡Gracias por señalar eso!
PeerBr
@Tu sentido común: solo asegúrate de que: ¿no va a buscar All () una mala idea si el conjunto de resultados es muy grande? ¿No sería mejor usar fetch () para obtener datos sucesivos?
timmornYE
@timmornYE eso es exactamente lo que se dice en el último párrafo de mi respuesta
Your Common Sense
21

Esto es muy tarde, pero me encontré con el problema y hago esto:

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

Es realmente simple y fácil. :)

Dan
fuente
19
Seleccionar todos los datos solo para contarlos va en contra de las reglas más básicas de interacción con la base de datos.
Su sentido común
Tal vez desee tener una barra de progreso para todos los valores devueltos, por lo que necesita saber el número de filas por adelantado.
Jonny
18

Terminé usando esto:

$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>";
}
Eric Warnke
fuente
12

Esta publicación es antigua, pero obtener recuento de filas en php con PDO es simple

$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
TenTen Peter
fuente
3
Consulte la documentación citada en la respuesta de karim79. Esto a veces funciona pero no es confiable.
octern
5

Esta es una publicación antigua, pero se frustra al buscar alternativas. Es muy desafortunado que PDO no tenga esta característica, especialmente porque PHP y MySQL tienden a ir de la mano.

Hay un defecto desafortunado en el uso de fetchColumn () ya que ya no puede usar ese conjunto de resultados (efectivamente) ya que fetchColumn () mueve la aguja a la siguiente fila. Entonces, por ejemplo, si tiene un resultado similar a

  1. Fruta-> Plátano
  2. Fruta-> Manzana
  3. Fruta-> Naranja

Si usa fetchColumn () puede descubrir que hay 3 frutas devueltas, pero si ahora recorre el resultado, solo tiene dos columnas. El precio de fetchColumn () es la pérdida de la primera columna de resultados solo para encontrar fuera cuántas filas fueron devueltas. Eso lleva a una codificación descuidada y resultados totalmente corregidos por errores si se implementa.

Así que ahora, usando fetchColumn () debe implementar una llamada y una consulta MySQL completamente nuevas solo para obtener un nuevo conjunto de resultados de trabajo. (que espero que no haya cambiado desde su última consulta), lo sé, poco probable, pero puede suceder. Además, la sobrecarga de consultas dobles en todas las validaciones de recuento de filas. Lo que para este ejemplo es pequeño, pero analizar 2 millones de filas en una consulta unida, no es un precio agradable a pagar.

Me encanta PHP y apoyo a todos los involucrados en su desarrollo, así como a la comunidad en general que usa PHP a diario, pero realmente espero que esto se aborde en futuras versiones. Esta es 'realmente' mi única queja con PHP PDO, que de lo contrario es una gran clase.

Eric
fuente
2

Respondiendo esto porque me atrapé con eso ahora sabiendo esto y tal vez sea útil.

Tenga en cuenta que no puede obtener resultados dos veces. Debe guardar el resultado de la búsqueda en la matriz, obtener el recuento de filas count($array)y generar resultados con foreach. Por ejemplo:

$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
    }                       
}
novato csharp
fuente
1

Si solo desea obtener un recuento de filas (no los datos), es decir. usando COUNT (*) en una declaración preparada, entonces todo lo que necesita hacer es recuperar el resultado y leer el valor:

$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)

En realidad, recuperar todas las filas (datos) para realizar un recuento simple es un desperdicio de recursos. Si el conjunto de resultados es grande, su servidor puede ahogarse en él.

pez loco
fuente
1

Para usar variables dentro de una consulta, debe usar bindValue()o bindParam(). Y no concatene las variables 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

Braian Coronel
fuente
0

Cuando se trata de mysql cómo contar u obtener cuántas filas en una tabla con PHP PDO , uso esto

// 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'];

los créditos van a Mike @ codeofaninja.com

Robert
fuente
-1

Una línea rápida para obtener la primera entrada devuelta. Esto es bueno para consultas muy básicas.

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

Referencia

itsazzad
fuente
-1

Intenté $count = $stmt->rowCount();con Oracle 11.2 y no funcionó. Decidí usar un bucle for como se muestra a continuación.

   $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;
manas mukherjee
fuente
-1

Para consultas directas donde quiero una fila específica y quiero saber si se encontró, utilizo algo como:

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;
}
usuario5862537
fuente
-1

Existe una solución simple. Si usa PDO, conéctese a su base de datos de esta manera:

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

Entonces, la consulta a DB será:

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

Y finalmente, para contar las filas que coinciden con su consulta, escriba así

$amountOfRows = $query->rowcount();
Vlad
fuente
¿Por qué esto me devuelve -1 la mayor parte del tiempo? Incluso si hay datos. .
Ingus
-1

fetchColumn ()

se usa si desea obtener el recuento de registros [effisien]

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

consulta()

se usa si desea recuperar datos y conteo de registros [opciones]

$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

antílope
fuente
Usted debe nunca hacer eso. En una mesa más o menos grande, consumirá toda la memoria de los servidores y bloqueará el servidor
su sentido común
Ahora su respuesta simplemente duplica una docena de respuestas existentes.
Su sentido común
-2

cuando haces un COUNT (*) en tu declaración mysql como en

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

su consulta mysql ya cuenta el número de resultados ¿por qué contar nuevamente en php? para obtener el resultado de tu mysql

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

y $nbcontendrá el número entero que ha contado con su declaración mysql un poco largo para escribir pero rápido para ejecutar

Editar: perdón por la publicación incorrecta, pero como ejemplo muestra la consulta con count in, estaba sugiriendo usar el resultado de mysql, pero si no usa el recuento en sql fetchAll () es eficiente, si guarda el resultado en una variable No perderás una línea.

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

count($table)devolverá el número de fila y aún puede usar el resultado después de dar like $row = $table[0] o usar unforeach

foreach($table as $row){
  print $row->id;
}
Surpriserom
fuente
1
La pregunta es cómo hacer un recuento cuando NO haces un CONTEO (*) en tu declaración mysql
Tu sentido común
-2

Aquí hay una extensión personalizada de la clase PDO, con una función auxiliar para recuperar el número de filas incluidas por el criterio "WHERE" de la última consulta.

Sin embargo, es posible que deba agregar más 'controladores', dependiendo de los comandos que use. En este momento solo funciona para consultas que usan "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();
    }
}
Venryx
fuente
El problema no vale un esfuerzo. Tal número se necesita tan raramente que uno no necesita una extensión dedicada. Sin mencionar que no admite declaraciones preparadas, la única razón para usar PDO.
Su sentido común
-2

Puede combinar el mejor método en una línea o función, y hacer que la nueva consulta se genere automáticamente para usted:

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

$numRows = getRowCount($query);
Bryan
fuente
Nada mejor en este método. Ejecutar una consulta adicional solo para saber cuántas filas se devolvieron no tiene ningún sentido.
Su sentido común
-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>
Amranur Rahman
fuente
1
Esta es una muy mala idea. Al seleccionar todas las filas, es una gran pérdida de ancho de 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; 
}
alpazull
fuente
-4

Use el parámetro array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL), de lo contrario muestre -1:

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

ejemplo:

$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;
Victor Idrogo Aliaga
fuente