Количество строк с PDO


192

Есть много противоречивых утверждений вокруг. Каков наилучший способ подсчета строк с использованием PDO в PHP? До использования PDO я просто пользовался mysql_num_rows.

fetchAll это то, чего я не хочу, потому что иногда я имею дело с большими наборами данных, поэтому не подходит для моего использования.

Есть ли у вас какие-либо предложения?

Ответы:


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

Не самый элегантный способ сделать это, плюс это требует дополнительного запроса.

Есть PDO PDOStatement::rowCount(), который, видимо, не работает в MySql. Вот это боль.

Из документа ЗОП:

Для большинства баз данных PDOStatement :: rowCount () не возвращает количество строк, затронутых оператором SELECT. Вместо этого используйте PDO :: query (), чтобы выдать оператор SELECT COUNT (*) с теми же предикатами, что и предполагаемый оператор SELECT, а затем используйте PDOStatement :: fetchColumn (), чтобы получить количество строк, которые будут возвращены. Ваше приложение может затем выполнить правильное действие.

РЕДАКТИРОВАТЬ: В приведенном выше примере кода используется подготовленный оператор, который во многих случаях, вероятно, не нужен для подсчета строк, поэтому:

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

это будет означать выполнение дополнительного запроса к базе данных. Я предполагаю, что он уже выполнил запрос на выборку и теперь хочет знать, сколько строк было возвращено.
Nickf

1
Никф правильно. mysql_num_rows () не будет работать при использовании PDO, правда?
Джеймс

Правда, по-видимому, есть PDOStatement :: rowCount (), но это не работает в MySql
karim79

11
Используя этот подход, fetchColumn()возвращает строку «1234» ... ваш EDIT имеет echo count($nRows);- count()это функция массива: P. Я также рекомендовал бы приведение типа fetchColumn()к целому числу. $count = (int) $stmt->fetchColumn()
Кобби

1
@ karim79 При неподготовленном утверждении оператор возвращает только 1 вместо фактического количества строк. Подготовленное заявление работает отлично. В чем может быть проблема?
SilentAssassin

86

Как я писал ранее в ответе на аналогичный вопрос , единственная причина mysql_num_rows()работала в том, что он извлекал все строки, чтобы дать вам эту информацию, даже если она вам не показалась.

Итак, в PDO, ваши варианты:

  1. Используйте FOUND_ROWS()функцию MySQL .
  2. Используйте fetchAll()функцию PDO для извлечения всех строк в массив, а затем используйте count()его.
  3. Сделайте дополнительный запрос SELECT COUNT(*), как предложено karim79.

8
Спасибо за то, что вы рассказали мне больше о mysql_num_rows (), похоже, это может быть важным узким местом, которое я давал себе. Еще раз спасибо.
Джеймс

2
fetch_all на самом деле это fetchAll () :)
динамический

2
Вариант 2 не рекомендуется, если результат большой.
Эдсон Орасио Джуниор

FOUND_ROWS () будет удален из MySQL, поэтому, пожалуйста, проверьте ссылку на FOUND_ROWS перед использованием, если вы уже знакомы с этим.
Анатак

29

Как это часто бывает, этот вопрос чертовски запутан. Люди приходят сюда, имея в виду две разные задачи :

  1. Они должны знать, сколько строк в таблице
  2. Они должны знать, возвращал ли запрос какие-либо строки

Это две абсолютно разные задачи, которые не имеют ничего общего и не могут быть решены одной и той же функцией. По иронии судьбы, ни для одного из нихPDOStatement::rowCount() нельзя использовать фактическую функцию.

Посмотрим почему

Подсчет строк в таблице

До использования PDO я просто пользовался mysql_num_rows().

Значит, ты уже сделал это неправильно. Использование mysql_num_rows()или rowCount()для подсчета количества строк в таблице является настоящей катастрофой с точки зрения использования ресурсов сервера. База данных должна прочитать все строки с диска, использовать память на сервере базы данных, а затем отправить всю эту кучу данных в PHP, также потребляя память процесса PHP, обременяя ваш сервер без всякой причины.
Кроме того, выбирать строки только для их подсчета просто бессмысленно. count(*)Запрос должен быть запущен вместо этого. База данных будет считать записи из индекса, не считывая фактические строки, а затем вернет только одну строку.

Для этого код, предложенный в принятом ответе, является справедливым.

Подсчет количества возвращенных строк.

Второй вариант использования не так катастрофичен, как довольно бессмысленный: в случае, если вам нужно знать, вернул ли ваш запрос какие-либо данные, у вас всегда есть эти данные!

Скажем, если вы выбираете только одну строку. Хорошо, вы можете использовать выбранную строку в качестве флага:

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

В случае, если вам нужно получить много строк, вы можете использовать fetchAll().

fetchAll() это то, чего я не хочу, так как иногда я имею дело с большими наборами данных

Да, конечно, для первого варианта использования это будет в два раза хуже. Но , как мы уже знаем, просто не выбрать строки только сосчитать, ни с rowCount()ниfetchAll() .

Но если вы собираетесь использовать выбранные строки, в этом нет ничего плохого fetchAll(). Помните, что в веб-приложении никогда не следует выделять огромное количество строк. Только строки, которые будут фактически использоваться на веб-странице, должны быть выбраны, следовательно, вы должны использовать LIMIT, WHEREили аналогичное предложение в вашем SQL. И для такого умеренного количества данных все в порядке fetchAll(). И снова, просто используйте результат этой функции в условии:

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

И, конечно, это будет абсолютное безумие, чтобы выполнить дополнительный запрос только для того, чтобы узнать, вернул ли ваш другой запрос какие-либо строки, как это было предложено в двух главных ответах.

Подсчет количества строк в большом наборе результатов

В таком редком случае, когда вам нужно выбрать действительно огромное количество строк (например, в консольном приложении), вы должны использовать небуферизованный запрос , чтобы уменьшить объем используемой памяти. Но это тот самый случай, когда rowCount() не будет доступно , поэтому эта функция также бесполезна.

Следовательно, это единственный случай использования, когда вам может потребоваться выполнить дополнительный запрос, если вам нужно знать приблизительную оценку количества выбранных строк.


это полезно, если API должен распечатать итоговые результаты поискового запроса. он вернет вам только 10 или 15 строк, но также должен сказать, что всего 284 результата.
Андрес СК

4
@andufo Это не так. Пожалуйста, помните: разработчик никогда не должен делать это таким образом. Поисковый запрос никогда не должен возвращать все 284 строки. 15 должны быть возвращены, чтобы показать, и одна строка из отдельного запроса, чтобы сказать, что 284 были найдены.
Твой здравый смысл

2
Это очень хороший момент - сначала не интуитивно понятный, но действительный. Большинство людей забывают, что два простых SQL-запроса работают намного быстрее, чем чуть больший. Чтобы оправдать любой подсчет, вам понадобится очень медленный запрос, который нельзя оптимизировать и который, вероятно, даст мало результатов. Спасибо что подметил это!
PeerBr

@ Ваш здравый смысл: Просто будьте уверены: не будет ли fetchAll () плохой идеей, если набор результатов очень большой? Не лучше ли использовать fetch () для последовательного получения данных.
timmornYE

@timmornYE, это именно то, что сказано в последнем абзаце моего ответа
Твой здравый смысл

21

Это супер поздно, но я столкнулся с проблемой, и я делаю это:

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

Это действительно просто и легко. :)


19
Выбор всех данных только для их подсчета противоречит самым основным правилам взаимодействия с базой данных.
Ваш здравый смысл

Возможно, вы хотите иметь индикатор выполнения для всех возвращаемых значений, поэтому вам нужно знать количество строк заранее.
Джонни

18

Я закончил тем, что использовал это:

$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

Этот пост старый, но получить количество строк в php с помощью PDO просто

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

3
Смотрите документацию, приведенную в ответе karim79. Это иногда работает, но не надежно.
октября

5

Это старый пост, но он разочарован поиском альтернативы. Очень жаль, что в PDO нет этой возможности, тем более что PHP и MySQL стремятся идти рука об руку.

К сожалению, в fetchColumn () есть недостаток, поскольку вы больше не можете использовать этот результирующий набор (эффективно), поскольку fetchColumn () перемещает стрелку к следующей строке. Так, например, если у вас есть результат, похожий на

  1. Фруктовое> Banana
  2. Фруктовое> Apple,
  3. Фруктовое> Оранжевый

Если вы используете fetchColumn (), вы можете обнаружить, что возвращены 3 плода, но если вы теперь перебираете результат, у вас есть только два столбца. Цена fetchColumn () - это потеря первого столбца результатов, чтобы найти сколько строк было возвращено. Это приводит к небрежному кодированию и полностью ошибочным результатам, если они реализованы.

Так что теперь, используя fetchColumn (), вы должны реализовать и совершенно новый вызов и MySQL запрос, чтобы получить свежий рабочий набор результатов. (что, надеюсь, не изменилось со времени вашего последнего запроса), я знаю, вряд ли, но это может произойти. Кроме того, накладные расходы двойных запросов на проверку всех строк. Что для этого примера невелико, но анализирует 2 миллиона строк в объединенном запросе, а это не приятная цена.

Я люблю PHP и поддерживаю всех, кто участвует в его разработке, а также сообщество в целом, использующее PHP на ежедневной основе, но очень надеюсь, что это будет решено в будущих выпусках. Это «действительно» моя единственная жалоба с PHP PDO, которая в остальном является отличным классом.


2

Отвечая на это, потому что я поймал себя в ловушку с этим, зная это, и, возможно, это будет полезно.

Имейте в виду, что вы не можете получить результаты дважды. Вы должны сохранить результаты выборки в массив, получить количество строк count($array)и вывести результаты с помощью foreach. Например:

$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

Если вы просто хотите получить количество строк (а не данные) т.е. используя COUNT (*) в подготовленном выражении, все, что вам нужно сделать, - это получить результат и прочитать значение:

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

На самом деле получение всех строк (данных) для простого подсчета является пустой тратой ресурсов. Если набор результатов велик, ваш сервер может подавиться им.



1

Чтобы использовать переменные в запросе, вы должны использовать bindValue()или bindParam(). И не объединяйте переменные с" . $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

Когда речь идет о MySQL, как подсчитать или получить, сколько строк в таблице с PHP PDO я использую это

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

кредиты идут на Майк @ codeofaninja.com


-1

Быстрый один лайнер, чтобы получить первую запись возвращается. Это хорошо для очень простых запросов.

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

Ссылка


-1

Я пытался $count = $stmt->rowCount();с Oracle 11.2, и он не работал. Я решил использовать цикл как показано ниже.

   $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

Для прямых запросов, где я хочу конкретную строку и хочу знать, была ли она найдена, я использую что-то вроде:

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

Есть простое решение. Если вы используете PDO, подключитесь к вашей БД следующим образом:

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

Тогда запрос к БД будет:

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

И, наконец, для подсчета строк, соответствующих вашему запросу, напишите так

$amountOfRows = $query->rowcount();

Почему это возвращает мне -1 в большинстве случаев? Даже если есть данные. ,
Ингус

-1

fetchColumn ()

используется, если хотите получить количество записей [effisien]

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

запроса ()

используется, если вы хотите получить данные и количество записей [опции]

$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


Вы никогда не должны делать это. На более-менее большом столе он поглотит всю память серверов и приведет к сбою сервера
Ваш здравый смысл

Теперь ваш ответ просто дублирует дюжину существующих ответов.
Ваш здравый смысл

-2

когда вы делаете COUNT (*) в вашем MySQL выражении, как в

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

Ваш запрос MySQL уже подсчитывает количество результатов, зачем снова считать в php? чтобы получить результат вашего mysql

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

и $nbбудет содержать целое число, которое вы посчитали с помощью оператора mysql, чтобы написать немного, но быстро выполнить

Редактировать: извините за неправильный пост, но, как показывают некоторые примеры запроса с счетчиком в, я предложил использовать результат mysql, но если вы не используете счетчик в sql, то fetchAll () эффективен, если вы сохраняете результат в переменной Вы не потеряете линию.

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

count($table)вернет номер строки, и вы все равно можете использовать результат после как $row = $table[0] или с помощьюforeach

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

1
Вопрос в том, как подсчитать, когда вы НЕ СДЕЛАЕТЕ СЧЕТ (*) в своем заявлении mysql
Твой здравый смысл

-2

Вот специальное расширение класса PDO с вспомогательной функцией для получения количества строк, включенных в критерии WHERE последнего запроса.

Возможно, вам придется добавить больше «обработчиков», в зависимости от того, какие команды вы используете. Прямо сейчас это работает только для запросов, которые используют «ОТ» или «ОБНОВЛЕНИЕ».

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

Проблема не стоит усилий. Такой номер нужен так редко, что не нужно выделенного расширения. Не говоря уже о том, что он не поддерживает подготовленные заявления - единственная причина для использования PDO.
Твой здравый смысл

-2

Вы можете объединить лучший метод в одну строку или функцию и автоматически сгенерировать новый запрос:

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

$numRows = getRowCount($query);

Ничего лучшего в этом методе. Выполнять дополнительный запрос только для того, чтобы узнать, сколько строк было возвращено, абсолютно бессмысленно.
Твой здравый смысл

-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
Это очень плохая идея. Выбор всех строк - это огромная трата пропускной способности.
Нафеес

-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

Используйте параметр array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL) , иначе покажите -1:

Усен параметр array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL) , грешить Элло продажа -1

пример:

$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;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.