Liczba wierszy z ChNP

192

Istnieje wiele sprzecznych ze sobą stwierdzeń. Jaki jest najlepszy sposób liczenia wierszy przy użyciu PDO w PHP? Przed użyciem PDO po prostu użyłem mysql_num_rows.

fetchAll jest czymś, czego nie chcę, ponieważ czasami mam do czynienia z dużymi zestawami danych, więc nie jest dobry na mój użytek.

Masz jakieś sugestie?

James
źródło

Odpowiedzi:

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

Nie jest to najbardziej elegancki sposób na to, a ponadto wymaga dodatkowego zapytania.

PDO ma PDOStatement::rowCount(), który najwyraźniej nie działa w MySql. Co za ból.

Z dokumentu PDO:

W przypadku większości baz danych funkcja PDOStatement :: rowCount () nie zwraca liczby wierszy, na które wpływa instrukcja SELECT. Zamiast tego użyj PDO :: query (), aby wydać instrukcję SELECT COUNT (*) z tymi samymi predykatami, co zamierzona instrukcja SELECT, a następnie użyj PDOStatement :: fetchColumn (), aby pobrać liczbę wierszy, które zostaną zwrócone. Twoja aplikacja może wtedy wykonać prawidłowe działanie.

EDYCJA: Powyższy przykład kodu używa przygotowanej instrukcji, która w wielu przypadkach jest prawdopodobnie niepotrzebna do liczenia wierszy, więc:

$nRows = $pdo->query('select count(*) from blah')->fetchColumn(); 
echo $nRows;
karim79
źródło
oznaczałoby to wykonanie dodatkowego zapytania do bazy danych. Zakładam, że wykonał już wybrane zapytanie i teraz chce wiedzieć, ile wierszy zostało zwróconych.
nickf
1
nickf ma rację. mysql_num_rows () nie będzie działał podczas używania PDO, prawda?
James
To prawda, że ​​podobno istnieje PDOStatement :: rowCount (), ale to nie działa w MySql
karim79
11
Przy takim podejściu fetchColumn()zwraca ciąg „1234” ... twoja EDYCJA ma echo count($nRows);- count()jest funkcją tablicową: P. Polecam także rzutowanie wyniku fetchColumn()na liczbę całkowitą. $count = (int) $stmt->fetchColumn()
Cobby
1
@ karim79 Nieprzygotowane podejście do instrukcji zwraca tylko 1 zamiast rzeczywistej liczby wierszy. Przygotowane oświadczenie działa dobrze. Co może być problemem?
SilentAssassin
86

Jak napisałem wcześniej w odpowiedzi na podobne pytanie , jedynym uzasadnionym powodem było mysql_num_rows()to, że wewnętrznie pobierało wszystkie wiersze, aby podać te informacje, nawet jeśli ci się to nie wydawało.

W PDO masz do wyboru następujące opcje:

  1. Użyj FOUND_ROWS()funkcji MySQL .
  2. Użyj fetchAll()funkcji PDO, aby pobrać wszystkie wiersze do tablicy, a następnie użyj count()jej.
  3. Wykonaj dodatkowe zapytanie SELECT COUNT(*), jak sugerował karim79.
Chad Birch
źródło
8
Dziękuję za pogłębienie mnie na temat mysql_num_rows () wygląda na to, że może to być ważne wąskie gardło, które sobie sam dawałem. Dzięki jeszcze raz.
James
2
fetch_all faktycznie jest fetchAll () :)
dynamiczny
2
Opcja 2 nie jest wskazana, jeśli wynik jest duży.
Edson Horacio Junior
FOUND_ROWS () zostanie usunięty z MySQL, więc zapoznaj się z linkiem do FOUND_ROWS przed użyciem tego, jeśli już to znasz.
anatak
29

Jak to często bywa, pytanie to jest mylące jak diabli. Ludzie przyjeżdżają tutaj z myślą o dwóch różnych zadaniach :

  1. Muszą wiedzieć, ile wierszy w tabeli
  2. Muszą wiedzieć, czy zapytanie zwróciło jakieś wiersze

To dwa absolutnie różne zadania, które nie mają ze sobą nic wspólnego i nie mogą być rozwiązane przez tę samą funkcję. Jak na ironię, dla żadnej z nichPDOStatement::rowCount() nie trzeba używać faktycznej funkcji.

Zobaczmy dlaczego

Zliczanie wierszy w tabeli

Przed użyciem PDO po prostu użyłem mysql_num_rows().

Oznacza to, że już źle to zrobiłeś. Użycie mysql_num_rows()lub rowCount()do zliczenia liczby wierszy w tabeli jest prawdziwą katastrofą pod względem zużycia zasobów serwera. Baza danych musi odczytać wszystkie wiersze z dysku, zużyć pamięć na serwerze bazy danych, a następnie wysłać całą tę stertę danych do PHP, zużywając również pamięć procesu PHP, obciążając serwer bez absolutnie żadnego powodu.
Poza tym wybieranie wierszy tylko do ich policzenia po prostu nie ma sensu. count(*)Zapytania ma być uruchamiany zamiast. Baza danych zliczy rekordy z indeksu, bez odczytywania rzeczywistych wierszy, a następnie zwrócony zostanie tylko jeden wiersz.

W tym celu kod sugerowany w zaakceptowanej odpowiedzi jest sprawiedliwy.

Zliczanie zwracanych wierszy.

Drugi przypadek użycia nie jest tak katastrofalny jak raczej bezcelowy: jeśli chcesz wiedzieć, czy zapytanie zwróciło jakieś dane, zawsze masz same dane!

Powiedz, jeśli wybierasz tylko jeden wiersz. W porządku, możesz użyć pobranego wiersza jako flagi:

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

Jeśli potrzebujesz wielu wierszy, możesz użyć fetchAll().

fetchAll() to coś, czego nie chcę, ponieważ czasami mam do czynienia z dużymi zestawami danych

Tak, oczywiście, w pierwszym przypadku użycia będzie dwa razy gorszy. Ale jak już się nauczyliśmy, po prostu nie zaznaczaj wierszy, aby je policzyć, ani z rowCount()ani fetchAll().

Ale jeśli rzeczywiście zamierzasz użyć wybranych wierszy, nie ma nic złego w użyciu fetchAll(). Pamiętaj, że w aplikacji internetowej nigdy nie należy wybierać dużej liczby wierszy. Tylko wiersze, które będą rzeczywiście wykorzystywane na stronie internetowej powinny być wybierane, stąd masz do wykorzystania LIMIT, WHERElub podobna klauzula w SQL. A w przypadku tak umiarkowanej ilości danych można z niego korzystać fetchAll(). I ponownie, po prostu użyj wyniku tej funkcji pod warunkiem:

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

I oczywiście absolutnym szaleństwem będzie uruchomienie dodatkowego zapytania tylko po to, aby stwierdzić, czy drugie zapytanie zwróciło jakieś wiersze, jak sugeruje to w dwóch najważniejszych odpowiedziach.

Zliczanie liczby wierszy w dużym zestawie wyników

W tak rzadkim przypadku, gdy trzeba wybrać naprawdę ogromną liczbę wierszy (na przykład w aplikacji konsolowej), musisz użyć niebuforowanego zapytania , aby zmniejszyć ilość używanej pamięci. Ale to jest rzeczywisty przypadek, kiedy rowCount() nie będzie dostępny , więc nie ma również zastosowania dla tej funkcji.

Dlatego jest to jedyny przypadek użycia, w którym może być konieczne uruchomienie dodatkowego zapytania, na wypadek, gdybyś musiał znać dokładne oszacowanie liczby wybranych wierszy.

Twój zdrowy rozsądek
źródło
przydaje się, jeśli interfejs API musi wydrukować łączne wyniki zapytania wyszukiwania. da ci tylko 10 lub 15 rzędów wstecz, ale także powinno powiedzieć, że jest 284 wyników ogółem.
Andres SK
4
@ andufo To nie jest. Pamiętaj: programista nigdy nie powinien robić tego w ten sposób. Wyszukiwane hasło nigdy nie powinno zwracać wszystkich 284 wierszy. 15 musi zostać zwróconych, aby pokazać, i jeden wiersz z oddzielnego zapytania, aby powiedzieć, że znaleziono 284.
Twój zdrowy rozsądek
2
To bardzo dobra uwaga - na początku nieintuicyjna, ale ważna. Większość ludzi zapomina, że ​​dwa proste zapytania SQL są znacznie szybsze niż nieco większe. Aby usprawiedliwić jakiekolwiek zliczanie, musisz mieć bardzo wolne zapytanie, którego nie można zoptymalizować i prawdopodobnie da niewiele wyników. Dzięki za zwrócenie na to uwagi!
PeerBr
@ Twój zdrowy rozsądek: Po prostu bądź pewien: czy fetchAll () nie będzie złym pomysłem, jeśli zestaw wyników jest bardzo duży? Czy nie lepiej byłoby użyć funkcji fetch (), aby uzyskać kolejne dane.
timmornYE
@timmornYE dokładnie to powiedziano w ostatnim akapicie mojej odpowiedzi
Your Common Sense
21

Jest bardzo późno, ale napotkałem problem i robię to:

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

To jest naprawdę proste i łatwe. :)

Dan
źródło
19
Wybranie wszystkich danych tylko w celu ich policzenia jest sprzeczne z najbardziej podstawowymi zasadami interakcji z bazą danych.
Twój zdrowy rozsądek
Być może chcesz mieć pasek postępu dla wszystkich zwracanych wartości, więc musisz znać liczbę wierszy z góry.
Jonny
18

Skończyło się na tym:

$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
źródło
12

Ten post jest stary, ale uzyskanie liczby wierszy w php z PDO jest proste

$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
TenTen Peter
źródło
3
Zobacz dokumentację cytowaną w odpowiedzi karim79. Czasami to działa, ale nie jest niezawodne.
octern
5

To jest stary post, ale denerwuję się, szukając alternatyw. To bardzo niefortunne, że PDO nie ma tej funkcji, zwłaszcza że PHP i MySQL zwykle idą w parze.

Korzystanie z fetchColumn () jest niefortunne, ponieważ nie można już używać tego zestawu wyników (skutecznie), ponieważ fetchColumn () przenosi igłę do następnego rzędu. Na przykład, jeśli masz wynik podobny do

  1. Owoce-> Banan
  2. Owoce-> Jabłko
  3. Owoc-> Pomarańczowy

Jeśli użyjesz fetchColumn (), możesz dowiedzieć się, że zostały zwrócone 3 owoce, ale jeśli teraz przejdziesz przez wynik, masz tylko dwie kolumny, Cena fetchColumn () to utrata pierwszej kolumny wyników tylko do znalezienia z ilu wierszy zostało zwróconych. Prowadzi to do niechlujnego kodowania i całkowicie błędnych wyników, jeśli zostaną zaimplementowane.

Tak więc teraz, używając fetchColumn (), musisz zaimplementować i całkowicie nowe wywołanie i zapytanie MySQL, aby uzyskać świeżo działający zestaw wyników. (który, mam nadzieję, nie zmienił się od czasu twojego ostatniego zapytania), wiem, mało prawdopodobne, ale może się zdarzyć. Ponadto narzut związany z podwójnymi zapytaniami przy sprawdzaniu poprawności liczby wierszy. Który w tym przykładzie jest mały, ale analizuje 2 miliony wierszy w połączonym zapytaniu, co nie jest przyjemną ceną do zapłacenia.

Uwielbiam PHP i wspieram wszystkich zaangażowanych w jego rozwój, a także całą społeczność używającą PHP na co dzień, ale naprawdę mam nadzieję, że zostanie to rozwiązane w przyszłych wydaniach. To „naprawdę” moja jedyna skarga na PHP PDO, która poza tym jest świetną klasą.

Eric
źródło
2

Odpowiadając na to, ponieważ złapałem się w to, wiedząc o tym i być może będzie to przydatne.

Pamiętaj, że nie możesz pobrać wyników dwukrotnie. Musisz zapisać wynik pobierania do tablicy, uzyskać liczbę wierszy według count($array)i wyświetlić wyniki za pomocą foreach. Na przykład:

$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
źródło
1

Jeśli chcesz tylko uzyskać liczbę wierszy (nie danych) tj. używając COUNT (*) w przygotowanej instrukcji, wystarczy pobrać wynik i odczytać wartość:

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

W rzeczywistości pobieranie wszystkich wierszy (danych) w celu wykonania prostej liczby jest marnotrawstwem zasobów. Jeśli zestaw wyników jest duży, serwer może się na nim zadławić.

madfish
źródło
1

Aby użyć zmiennych w zapytaniu, musisz użyć bindValue()lub bindParam(). I nie łącz ze sobą zmiennych" . $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
źródło
0

Kiedy chodzi o mysql, jak liczyć lub uzyskać liczbę wierszy w tabeli z PHP PDO , używam tego

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

kredyty trafiają do Mike @ codeofaninja.com

Robert
źródło
-1

Szybka linijka umożliwiająca zwrot pierwszego wpisu. Jest to przydatne w przypadku bardzo podstawowych zapytań.

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

Odniesienie

itsazzad
źródło
-1

Próbowałem $count = $stmt->rowCount();z Oracle 11.2 i to nie działało. Zdecydowałem się użyć pętli for, jak pokazano poniżej.

   $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
źródło
-1

Do prostych zapytań, w których chcę określony wiersz i chcę wiedzieć, czy został znaleziony, używam czegoś takiego:

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;
}
użytkownik5862537
źródło
-1

Istnieje proste rozwiązanie. Jeśli używasz PDO, połącz się z DB tak:

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

Następnie zapytanie do DB będzie:

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

I na koniec, aby policzyć wiersze pasujące do zapytania, napisz w ten sposób

$amountOfRows = $query->rowcount();
Vlad
źródło
Dlaczego zwraca mi -1 przez większość czasu? Nawet jeśli są dane. .
Ingus
-1

fetchColumn ()

używane, jeśli chcesz uzyskać liczbę rekordów [effisien]

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

pytanie()

używane, jeśli chcesz pobrać dane i liczbę rekordów [opcje]

$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

antylopa
źródło
Nigdy nie powinieneś tego robić. Na mniejszym lub większym stole zajmie całą pamięć serwerów i spowoduje awarię serwera
Twoje wspólne zmysły
Teraz twoja odpowiedź powiela tuzin istniejących odpowiedzi.
Twój zdrowy rozsądek
-2

kiedy wykonasz COUNT (*) w instrukcji mysql jak w

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

twoje zapytanie mysql już liczy liczbę wyników, po co ponownie liczyć w php? aby uzyskać wynik swojego mysql

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

i $nbbędzie zawierał liczbę całkowitą, którą policzyłeś za pomocą instrukcji mysql, nieco długi do napisania, ale szybki do wykonania

Edycja: przepraszam za niewłaściwy post, ale jako przykład pokazuję zapytanie z licznikiem, sugerowałem użycie wyniku mysql, ale jeśli nie użyjesz licznika w sql, funkcja fetchAll () jest wydajna, jeśli zapiszesz wynik w zmiennej nie stracisz linii.

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

count($table)zwróci liczbę wierszy i nadal możesz użyć wyniku po polubieniu $row = $table[0] lub użyciuforeach

foreach($table as $row){
  print $row->id;
}
Surpriserom
źródło
1
Pytanie brzmi: jak policzyć, kiedy NIE ZLICZASZ (*) w swoim wyciągu mysql
Twój zdrowy rozsądek
-2

Oto niestandardowe rozszerzenie klasy PDO z funkcją pomocniczą do pobierania liczby wierszy objętych kryteriami „GDZIE” z ostatniego zapytania.

Może być jednak konieczne dodanie większej liczby „modułów obsługi”, w zależności od używanych poleceń. Obecnie działa tylko w przypadku zapytań korzystających z „FROM” lub „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
źródło
Problem nie jest wart wysiłku. Taki numer jest potrzebny tak rzadko, że nie trzeba dedykowanego rozszerzenia. Nie wspominając o tym, że nie obsługuje przygotowanych instrukcji - to jedyny powód do używania PDO.
Twój zdrowy rozsądek
-2

Możesz połączyć najlepszą metodę w jedną linię lub funkcję i automatycznie wygenerować nowe zapytanie:

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
źródło
Nic najlepszego w tej metodzie. Uruchomienie dodatkowego zapytania tylko w celu sprawdzenia, ile wierszy zostało zwróconych, nie ma absolutnie żadnego sensu.
Twój zdrowy rozsądek
-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
źródło
1
To naprawdę zły pomysł. Wybór wszystkich wierszy powoduje ogromne marnotrawstwo przepustowości.
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
źródło
-4

Użyj parametru array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL), w przeciwnym razie pokaż -1:

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

przykład:

$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
źródło