Contagem de linhas com DOP

192

Existem muitas declarações conflitantes por aí. Qual é a melhor maneira de contar linhas usando DOP em PHP? Antes de usar o DOP, simplesmente usei mysql_num_rows.

fetchAll é algo que eu não quero, porque às vezes posso lidar com grandes conjuntos de dados, portanto não é bom para o meu uso.

Você tem alguma sugestão?

James
fonte

Respostas:

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

Não é a maneira mais elegante de fazer isso, além de envolver uma consulta extra.

O DOP possui PDOStatement::rowCount(), o que aparentemente não funciona no MySQL. Que dor.

Do documento DOP:

Para a maioria dos bancos de dados, PDOStatement :: rowCount () não retorna o número de linhas afetadas por uma instrução SELECT. Em vez disso, use PDO :: query () para emitir uma instrução SELECT COUNT (*) com os mesmos predicados que a instrução SELECT pretendida, depois use PDOStatement :: fetchColumn () para recuperar o número de linhas que serão retornadas. Seu aplicativo pode executar a ação correta.

EDIT: O exemplo de código acima usa uma instrução preparada, que em muitos casos é provavelmente desnecessária para a contagem de linhas, portanto:

$nRows = $pdo->query('select count(*) from blah')->fetchColumn(); 
echo $nRows;
karim79
fonte
isso significaria fazer uma consulta extra ao banco de dados. Suponho que ele já fez uma consulta de seleção e agora quer saber quantas linhas foram retornadas.
nickf
1
nickf está correto. mysql_num_rows () não funcionará ao usar o PDO, mas funcionará?
1919 James James
É verdade, aparentemente há PDOStatement :: rowCount (), mas que não funciona no MySql
karim79
11
Usando esta abordagem, fetchColumn()retorna uma string "1234" ... sua EDIT possui echo count($nRows);- count()é uma função de matriz: P. Eu também recomendo digitar o resultado de fetchColumn()um número inteiro. $count = (int) $stmt->fetchColumn()
Cobby 26/05
1
@ karim79 A abordagem de declaração não preparada está retornando apenas 1 em vez do número real de linhas. A declaração preparada funciona bem. O que pode ser o problema ?
SilentAssassin
86

Como escrevi anteriormente em uma resposta a uma pergunta semelhante , a única razão pela qual mysql_num_rows()funcionou é porque ele buscava internamente todas as linhas para fornecer essas informações, mesmo que não parecesse isso para você.

Portanto, na DOP, suas opções são:

  1. Use a FOUND_ROWS()função do MySQL .
  2. Use a fetchAll()função do PDO para buscar todas as linhas em uma matriz e use count()nela.
  3. Faça uma consulta extra para SELECT COUNT(*), como karim79 sugeriu.
Chad Birch
fonte
8
Obrigado por me educar mais sobre mysql_num_rows () parece que esse pode ser um gargalo importante que eu estava me dando. Obrigado novamente.
194/09 James
2
fetch_all realmente é fetchAll () :)
dinâmica
2
A opção 2 não é aconselhável se o resultado for grande.
Edson Horacio Junior
O FOUND_ROWS () será removido do MySQL, portanto, verifique o link para FOUND_ROWS antes de usá-lo, se você já estiver familiarizado com isso.
anatak
28

Como costuma acontecer, essa pergunta é confusa como o inferno. As pessoas estão vindo para cá com duas tarefas diferentes em mente:

  1. Eles precisam saber quantas linhas na tabela
  2. Eles precisam saber se uma consulta retornou alguma linha

São duas tarefas absolutamente diferentes que não têm nada em comum e não podem ser resolvidas pela mesma função. Ironicamente, para nenhum deles, a PDOStatement::rowCount()função real deve ser usada.

Vamos ver porque

Contando linhas na tabela

Antes de usar o DOP, simplesmente usei mysql_num_rows().

Significa que você fez errado. Usar mysql_num_rows()ou rowCount()contar o número de linhas na tabela é um desastre real em termos de consumo dos recursos do servidor. Um banco de dados precisa ler todas as linhas do disco, consumir a memória no servidor de banco de dados e enviar toda essa pilha de dados para o PHP, consumindo também a memória do processo do PHP, sobrecarregando o servidor sem motivo.
Além disso, selecionar linhas apenas para contá-las simplesmente não faz sentido. Uma count(*)consulta deve ser executada. O banco de dados contará os registros do índice, sem ler as linhas reais e, em seguida, apenas uma linha retornada.

Para esse fim, o código sugerido na resposta aceita é justo.

Contando o número de linhas retornadas.

O segundo caso de uso não é tão desastroso quanto inútil: caso você precise saber se sua consulta retornou algum dado, você sempre terá os dados em si!

Digamos, se você estiver selecionando apenas uma linha. Tudo bem, você pode usar a linha buscada como um sinalizador:

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

Caso você precise obter muitas linhas, poderá usá-lo fetchAll().

fetchAll() é algo que eu não vou querer, pois às vezes posso lidar com grandes conjuntos de dados

Sim, é claro, para o primeiro caso de uso, seria duas vezes pior. Mas, como já aprendemos, não selecione as linhas apenas para contá-las, nem com rowCount()nem fetchAll().

Mas no caso de você realmente usar as linhas selecionadas, não há nada errado em usar fetchAll(). Lembre-se de que em um aplicativo Web você nunca deve selecionar uma quantidade enorme de linhas. Somente linhas que serão efectivamente utilizados em uma página web deve ser selecionado, portanto, você tem que uso LIMIT, WHEREou uma cláusula semelhante em seu SQL. E para uma quantidade tão moderada de dados, tudo bem em usar fetchAll(). E, novamente, basta usar o resultado desta função na condição:

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

E é claro que será uma loucura absoluta executar uma consulta extra apenas para saber se sua outra consulta retornou alguma linha, conforme sugerido nas duas principais respostas.

Contando o número de linhas em um grande conjunto de resultados

Em um caso tão raro, quando você precisa selecionar uma quantidade enorme de linhas (em um aplicativo de console, por exemplo), é necessário usar uma consulta sem buffer , para reduzir a quantidade de memória usada. Mas este é o caso real quando rowCount() não estará disponível , portanto, não há uso para essa função também.

Portanto, esse é o único caso de uso em que talvez você precise executar uma consulta extra, caso precise conhecer uma estimativa aproximada do número de linhas selecionadas.

Seu senso comum
fonte
é útil se a API precisar imprimir o total de resultados de uma consulta de pesquisa. ele retornará apenas 10 ou 15 linhas, mas também informará que existem 284 resultados no total.
Andres SK
4
@andufo Não é. Lembre-se: um desenvolvedor nunca deve fazer dessa maneira. A consulta de pesquisa nunca deve retornar todas as 284 linhas. 15 devem ser retornados para mostrar e uma linha da consulta separada para informar que 284 foram encontrados.
Seu senso comum
2
Esse é um argumento muito bom - não intuitivo a princípio, mas válido. A maioria das pessoas esquece que duas consultas SQL simples são muito mais rápidas que as ligeiramente maiores. Para justificar qualquer contagem, você precisará ter uma consulta muito lenta que não possa ser otimizada e provavelmente produzirá poucos resultados. Obrigado por apontar isso!
precisa saber é o seguinte
@ Seu senso comum: Apenas tenha certeza: fetchAll () não será uma má idéia se o conjunto de resultados for muito grande? Não seria melhor usar fetch () para obter dados sucessivos.
timmornYE
@timmornYE isso é exatamente o que foi dito no último parágrafo da minha resposta
Seu senso comum
21

Isso é muito tarde, mas encontrei o problema e faço o seguinte:

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

É realmente simples e fácil. :)

Dan
fonte
19
Selecionar todos os dados apenas para contá-los é contra as regras mais básicas de interação com o banco de dados.
Seu senso comum
Talvez você queira ter uma barra de progresso para todos os valores retornados, portanto, é necessário conhecer o número de linhas antecipadamente.
31519 Jonny
18

Acabei usando isso:

$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
fonte
12

Esta publicação é antiga, mas Obter contagem de linhas em php com DOP é simples

$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
TenTen Peter
fonte
3
Veja a documentação citada na resposta de karim79. Às vezes, isso funciona, mas não é confiável.
Oct 07/07
5

Este é um post antigo, mas está ficando frustrado em busca de alternativas. É lamentável que o DOP não tenha esse recurso, especialmente porque o PHP e o MySQL tendem a andar de mãos dadas.

Existe uma falha infeliz no uso de fetchColumn (), pois você não pode mais usar esse conjunto de resultados (efetivamente), pois o fetchColumn () move a agulha para a próxima linha. Por exemplo, se você tiver um resultado semelhante a

  1. Frutas-> Banana
  2. Frutas-> Maçã
  3. Frutas-> Laranja

Se você usar fetchColumn (), poderá descobrir que há três frutas retornadas, mas se agora percorrer o resultado, terá apenas duas colunas. O preço de fetchColumn () é a perda da primeira coluna de resultados apenas para encontrar de quantas linhas foram retornadas. Isso leva à codificação desleixada e a resultados totalmente errados, se implementados.

Então agora, usando fetchColumn (), você precisa implementar uma chamada totalmente nova e uma consulta MySQL apenas para obter um novo conjunto de resultados de trabalho. (que, espero, não tenha sido alterado desde sua última consulta), eu sei, improvável, mas isso pode acontecer. Além disso, a sobrecarga de consultas duplas na validação de todas as linhas. Que neste exemplo é pequeno, mas analisa 2 milhões de linhas em uma consulta unida, não é um preço agradável a pagar.

Eu amo PHP e apoio todos os envolvidos em seu desenvolvimento, bem como a comunidade em geral, usando PHP diariamente, mas realmente espero que isso seja resolvido em versões futuras. Esta é 'realmente' a minha única reclamação com o PHP PDO, que de outra forma é uma ótima classe.

Eric
fonte
2

Respondendo a isso porque eu me prendi a ela agora, sabendo disso e talvez seja útil.

Lembre-se de que você não pode buscar resultados duas vezes. Você precisa salvar o resultado da busca na matriz, obter a contagem de linhas count($array)e gerar resultados com foreach. Por exemplo:

$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
    }                       
}
csharp newbie
fonte
1

Se você quiser apenas obter uma contagem de linhas (não os dados), por exemplo. usando COUNT (*) em uma instrução preparada, tudo o que você precisa fazer é recuperar o resultado e ler o 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)

Na verdade, recuperar todas as linhas (dados) para executar uma contagem simples é um desperdício de recursos. Se o conjunto de resultados for grande, seu servidor poderá engasgar.

peixe maluco
fonte
1

Para usar variáveis ​​em uma consulta, você deve usar bindValue()ou bindParam(). E não concatenar as variáveis ​​com" . $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
fonte
0

Quando se trata de mysql como contar ou obter quantas linhas em uma tabela com o PHP PDO eu uso este

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

créditos vão para Mike @ codeofaninja.com

Robert
fonte
-1

Um forro rápido para obter a primeira entrada retornada. Isso é bom para consultas muito básicas.

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

Referência

itsazzad
fonte
-1

Eu tentei $count = $stmt->rowCount();com o Oracle 11.2 e não funcionou. Decidi usar um loop for, como mostrado abaixo.

   $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
fonte
-1

Para consultas diretas em que desejo uma linha específica e quero saber se foi encontrada, uso 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;
}
user5862537
fonte
-1

Há uma solução simples. Se você usa o DOP, conecte-se ao seu banco de dados da seguinte maneira:

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

Em seguida, a consulta ao DB será:

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

E, finalmente, para contar as linhas correspondentes à sua consulta, escreva assim

$amountOfRows = $query->rowcount();
Vlad
fonte
Por que isso me devolve -1 na maioria das vezes? Mesmo se houver dados. .
Ingus 07/04
-1

fetchColumn ()

usado se quiser obter a contagem do registro [effisien]

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

inquerir()

usado se desejar recuperar dados e contagem de registros [opções]

$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

antelove
fonte
Você nunca deve fazer isso. Em uma tabela mais ou menos grande, ela consome toda a memória dos servidores e trava o servidor
Your Common Sense
Agora sua resposta duplica apenas uma dúzia de respostas existentes.
Seu senso comum
-2

quando você cria COUNT (*) na sua instrução mysql como em

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

sua consulta mysql já está contando o número de resultados por que contar novamente em php? para obter o resultado do seu mysql

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

e $nbconterá o número inteiro que você contou com sua instrução mysql um pouco longo para escrever, mas rápido para executar

Edit: desculpe pela postagem errada, mas como algum exemplo mostra consulta com count in, eu estava sugerindo o uso do resultado do mysql, mas se você não usar a contagem no sql fetchAll () é eficiente, se você salvar o resultado em uma variável você não perderá uma linha.

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

count($table)retornará o número de linha e você ainda poderá usar o resultado depois de gostar $row = $table[0] ou usar umforeach

foreach($table as $row){
  print $row->id;
}
Surpriserom
fonte
1
A questão é como obter contagem quando você NÃO CONCORDA (*) em sua instrução mysql
Seu senso comum
-2

Aqui está uma extensão personalizada da classe PDO, com uma função auxiliar para recuperar o número de linhas incluídas pelos critérios "WHERE" da última consulta.

Você pode precisar adicionar mais 'manipuladores', dependendo de quais comandos você usa. No momento, ele funciona apenas para consultas que usam "FROM" ou "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
fonte
O problema não vale a pena. Tal número é necessário tão raramente que não é necessário uma extensão dedicada. Sem mencionar que não suporta declarações preparadas - o único motivo para usar o DOP.
Seu senso comum
-2

Você pode combinar o melhor método em uma linha ou função e gerar a nova consulta automaticamente:

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
fonte
Nada melhor neste método. Executar uma consulta extra apenas para saber quantas linhas foram retornadas não faz absolutamente nenhum sentido.
Seu senso comum
-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
fonte
1
Esta é uma péssima ideia. Selecionando todas as linhas, é um enorme desperdício de largura 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
fonte
-4

Use o parâmetro array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL), senão mostre -1:

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

exemplo:

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