Підрахунок рядків із 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. Який біль.

З документа PDO:

У більшості баз даних PDOStatement :: rowCount () не повертає кількість рядків, на які впливає оператор SELECT. Замість цього використовуйте PDO :: query (), щоб надати оператор SELECT COUNT (*) з тими самими предикатами, що й призначений для вас оператор SELECT, а потім використовуйте PDOStatement :: fetchColumn () для отримання кількості рядків, які будуть повернуті. Тоді ваша програма може виконати правильну дію.

EDIT: У наведеному вище прикладі коду використовується підготовлений вислів, який у багатьох випадках, ймовірно, є непотрібним для підрахунку рядків, тому:

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

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, перш ніж використовувати це, якщо ви вже були знайомі з цим.
anatak

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. Фрукти-> Банан
  2. Фрукти-> Яблуко
  3. Фрукти-> Апельсин

Якщо ви використовуєте fetchColumn (), ви можете дізнатись, що повернуто 3 фрукти, але якщо ви переглянете результат, у вас є лише два стовпці. скільки рядків було повернуто Це призводить до неохайного кодування та до повних результатів, що позбавлені помилок, якщо вони реалізовані.

Тож тепер, використовуючи 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();

ГЛ


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


Ви ніколи не повинні цього робити. На більш-менш великій таблиці він з’їсть всю пам'ять серверів і розбить сервер
Your Common Sense

Тепер ваша відповідь просто дублює десяток існуючих відповідей.
Твій здоровий глузд

-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] або використання aforeach

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
Це справді погана ідея. Вибираючи всі рядки, це величезна трата пропускної здатності.
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

Використовувати параметр array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL) , інакше покажіть -1:

Параметр Usen array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL) Usen, продаж елло -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.