PDO的行数


192

周围有许多矛盾的说法。在PHP中使用PDO进行行计数的最佳方法是什么?在使用PDO之前,我只是简单地使用mysql_num_rows

fetchAll 这是我不想要的东西,因为有时我可能要处理大型数据集,因此对我的使用不利。

你有什么建议吗?

Answers:


264
$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语句相同的谓词的SELECT COUNT(*)语句,然后使用PDOStatement :: fetchColumn()检索将返回的行数。然后,您的应用程序可以执行正确的操作。

编辑:上面的代码示例使用一个准备好的语句,在许多情况下,出于计数行的目的可能是不必要的,因此:

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

这意味着要进行额外的数据库查询。我假设他已经完成了选择查询,现在想知道返回了多少行。
尼克

1
尼克是正确的。mysql_num_rows()在使用PDO时无法使用,可以吗?
詹姆斯

是的,显然有PDOStatement :: rowCount(),但在MySql中不起作用
karim79,2009年

11
使用这种方法,fetchColumn()返回一个字符串“1234” ......您的编辑echo count($nRows);- count()是一个数组功能:P。我也建议将结果类型强制转换为fetchColumn()整数。$count = (int) $stmt->fetchColumn()
科比,

1
@ karim79非准备语句方法仅返回1,而不是实际的行数。准备好的语句工作正常。可能是什么问题?
SilentAssassin

86

正如我先前在回答类似问题时所写的那样,mysql_num_rows()起作用的唯一原因是因为它是在内部获取所有行以为您提供该信息,即使您看起来不喜欢它也是如此。

因此,在PDO中,您可以选择:

  1. 使用MySQL的FOUND_ROWS()功能。
  2. 使用PDO的fetchAll()功能将所有行提取到数组中,然后count()在其上使用。
  3. SELECT COUNT(*)根据karim79的建议,对进行额外的查询。

8
感谢您进一步教育我有关mysql_num_rows()的信息,这可能是我给自己的一个重要瓶颈。再次感谢。
詹姆斯

2
fetch_all实际上是fetchAll():)
动态

2
如果结果很大,则不建议使用选项2。
Edson Horacio Junior

FOUND_ROWS()将从MySQL中删除,因此如果您已经熟悉FOUND_ROWS,请在使用前检查FOUND_ROWS的链接。
阿纳塔克

28

由于经常发生,这个问题令人困惑。人们来到这里时会想到两个不同的任务

  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()。请记住,在Web应用程序中,绝对不要选择大量的行。只有这样才能在网页上实际使用的行应选择,因此你一定要使用LIMITWHERE或在您的SQL类似的条款。对于如此少量的数据,就可以使用fetchAll()。同样,只需在以下条件下使用此函数的结果:

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

当然,运行一个额外的查询只是为了告诉您其他查询是否返回了任何行,这绝对是疯狂的做法,正如两个最佳答案中所建议的那样。

计算大型结果集中的行数

在这种罕见的情况下,当您需要选择大量的行(例如在控制台应用程序中)时,必须使用无缓冲查询,以减少所使用的内存量。但是,这是在实际情况下rowCount() 将无法使用,因而有此功能没有使用为好。

因此,这是唯一的用例,当您可能需要运行额外的查询时,以防需要了解所选行数的近似估计。


如果API需要打印出搜索查询的全部结果,则很有用。它只会给您10或15行,但是它也应该告诉您总共有284条结果。
Andres SK

4
@andufo不是。请记住:一个开发商应该永远不会做这种方式。搜索查询永远不要返回所有284行。15已经返回到显示和一个由单独的查询行告诉284被发现。
常识

2
这是一个很好的观点-一开始并不直观,但是很有效。大多数人忘记了两个简单的SQL查询的方式比一个稍微大一点的速度更快。为了证明任何计数的合理性,您必须要有一个非常慢的查询,该查询无法优化,并且可能会产生很少的结果。感谢您指出了这一点!
PeerBr 2014年

@您的常识:可以肯定的是:如果结果集很大,fetchAll()会不是一个坏主意吗?那么最好使用fetch()连续获取数据。
timmornYE '16

@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
仅选择所有数据进行计数是违反数据库交互的最基本规则的。
您的常识2016年

也许您想为所有返回值提供一个进度条,所以您需要预先知道行数。
强尼

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

这篇文章很老,但是用PDO在php中获取行数很简单

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

3
请参阅karim79的答案中引用的文档。有时这可行,但不可靠。
octern

5

这是一则旧文章,但在寻找替代品时感到沮丧。不幸的是,PDO缺少此功能,尤其是在PHP和MySQL趋于齐头并进的情况下。

不幸的是,使用fetchColumn()有一个缺陷,因为当fetchColumn()将指针移至下一行时,您将无法再有效地使用该结果集。例如,如果您得到的结果类似于

  1. 水果->香蕉
  2. 水果->苹果
  3. 水果->橙色

如果使用fetchColumn(),您会发现返回了3个水果,但是如果现在循环遍历结果,则只有两列,而fetchColumn()的价格就是结果第一列的损失返回多少行。这导致草率的编码,并且如果实施的话,将导致完全出错的结果。

因此,现在,必须使用fetchColumn()来实现一个全新的调用和MySQL查询,以获取新的工作结果集。(希望自您上次查询以来没有改变),我知道,虽然不太可能,但它可能会发生。同样,在所有行计数验证中双重查询的开销。在此示例中,这很小,但是在联接的查询上解析了200万行,这并不是一个合理的代价。

我热爱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'];

学分归于Mike @ codeofaninja.com


-1

快速的班轮让第一个条目返回。这对于非常基本的查询非常有用。

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

参考


-1

我尝试$count = $stmt->rowCount();使用Oracle 11.2,但无法正常工作。我决定使用如下所示的for循环。

   $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

当您在mysql语句中输入COUNT(*)时,例如

$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] 或使用a 之后使用结果foreach

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

1
问题是当您不在mysql语句中未进行COUNT(*)时如何计数
您的常识

-2

这是PDO类的自定义扩展,具有帮助程序功能来检索上一个查询的“ WHERE”条件所包含的行数。

但是,根据您使用的命令,您可能需要添加更多的“处理程序”。现在,它仅适用于使用“ FROM”或“ 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();
    }
}

这个问题不值得努力。如此数量的需求很少,因此不需要专用的扩展名。更不用说它不支持准备好的语句-使用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:

用例参数 array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL),sin ello sale -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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.