来自PDO手册:
PDOStatement::rowCount() 返回 受最后一个影响的行数删除、插入或更新语句 由相应的 PDOStatement object.
如果最后一个 SQL 语句执行者 相关的PDOStatement是一个 SELECT 语句,某些数据库可能会 返回的行数 那句话。然而,这 并非所有人的行为都得到保证 数据库,不应依赖 适用于便携式应用。
我最近才发现这一点。我刚刚将我的数据库抽象层更改为不再使用SELECT COUNT(1) ...
,因为只需查询实际行然后计算结果会更有效。现在PDO不支持!?
我不将PDO用于MySQL和PgSQL,但我使用SQLite。有没有办法(在不完全更改 dbal 的情况下)在 PDO 中像这样计算行?在MySQL中,这将是这样的:
$q = $db->query('SELECT a, b, c FROM tbl WHERE oele = 2 GROUP BY boele');
$rows = $q->num_rows;
// and now use $q to get actual data
使用MySQLi和PgSQL驱动程序,这是可能的。对于所有的PDO不是!?
附言。我最初的解决方案是扩展SQLResult->count方法(我自己的方法)以SELECT COUNT(1) FROM
替换SELECT ... FROM
并返回该数字(效率非常低,但仅适用于SQLite PDO)。但这还不够好,因为在上面的示例中查询是一个GROUP BY
,它会改变COUNT(1)
的含义/功能。
这是适合您的解决方案
$sql="SELECT count(*) FROM [tablename] WHERE key == ? ";
$sth = $this->db->prepare($sql);
$sth->execute(array($key));
$rows = $sth->fetch(PDO::FETCH_NUM);
echo $rows[0];
内存效率有点低,但如果你无论如何都在使用数据,我经常使用它:
$rows = $q->fetchAll();
$num_rows = count($rows);
我最终使用的方法非常简单:
$query = 'SELECT a, b, c FROM tbl WHERE oele = 2 GROUP BY boele';
$nrows = $db->query("SELECT COUNT(1) FROM ($query) x")->fetchColumn();
可能不是最有效的,但它似乎是万无一失的,因为它实际上计算了原始查询的结果。
我不将PDO用于MySQL和PgSQL,但我使用SQLite。有没有办法(在不完全更改 dbal 的情况下)在 PDO 中像这样计算行?
根据此评论,SQLite 问题是由 3.x 中的 API 更改引入的。
也就是说,您可能需要在使用 PDO 之前检查它实际上是如何实现该功能的。
我不熟悉它的内部结构,但我对PDO解析您的SQL的想法持怀疑态度(因为SQL语法错误会出现在数据库的日志中),更不用说尝试对它进行最轻微的意义了使用最佳策略计算行数。
假设它确实没有,那么在 select 语句中返回所有适用行计数的现实策略包括从 SQL 语句中对限制子句进行字符串操作,以及以下任一:
- 在其上运行 select count() 作为子查询(从而避免您在 PS 中描述的问题);
- 打开游标,运行 fetch all 并计算行数;或
- 首先打开这样的游标,并同样计算剩余的行。
但是,更好的计数方法是执行将执行此操作的完全优化的查询。通常情况下,这意味着重写您尝试分页的初始查询的有意义的块 - 去除不需要的字段并按操作排序等。
最后,如果您的数据集足够大,可以计算任何类型的滞后,您可能还需要调查返回从统计信息派生的估计值,和/或定期将结果缓存在 Memcache 中。在某些时候,拥有精确正确的计数不再有用......
,PDOStatement
是Traversable
。给定一个查询:
$query = $dbh->query('
SELECT
*
FROM
test
');
它可以迭代:
$it = new IteratorIterator($query);
echo '<p>', iterator_count($it), ' items</p>';
// Have to run the query again unfortunately
$query->execute();
foreach ($query as $row) {
echo '<p>', $row['title'], '</p>';
}
或者你可以做这样的事情:
$it = new IteratorIterator($query);
$it->rewind();
if ($it->valid()) {
do {
$row = $it->current();
echo '<p>', $row['title'], '</p>';
$it->next();
} while ($it->valid());
} else {
echo '<p>No results</p>';
}
如果你愿意放弃一丝抽象,那么你可以使用一个自定义包装类,它只是将所有内容传递给PDO。 说,像这样:(警告,代码未经测试)
class SQLitePDOWrapper
{
private $pdo;
public function __construct( $dns, $uname = null, $pwd = null, $opts = null )
{
$this->pdo = new PDO( $dns, $unam, $pwd, $opts );
}
public function __call( $nm, $args )
{
$ret = call_user_func_array( array( $this->pdo, $nm ), $args );
if( $ret instanceof PDOStatement )
{
return new StatementWrapper( $this, $ret, $args[ 0 ] );
// I'm pretty sure args[ 0 ] will always be your query,
// even when binding
}
return $ret;
}
}
class StatementWrapper
{
private $pdo; private $stat; private $query;
public function __construct( PDO $pdo, PDOStatement $stat, $query )
{
$this->pdo = $pdo;
$this->stat = $stat;
this->query = $query;
}
public function rowCount()
{
if( strtolower( substr( $this->query, 0, 6 ) ) == 'select' )
{
// replace the select columns with a simple 'count(*)
$res = $this->pdo->query(
'SELECT COUNT(*)' .
substr( $this->query,
strpos( strtolower( $this->query ), 'from' ) )
)->fetch( PDO::FETCH_NUM );
return $res[ 0 ];
}
return $this->stat->rowCount();
}
public function __call( $nm, $args )
{
return call_user_func_array( array( $this->stat, $nm ), $args );
}
}
也许这会为你解决问题?
$FoundRows = $DataObject->query('SELECT FOUND_ROWS() AS Count')->fetchColumn();
你必须使用 rowCount — 返回受上一条 SQL 语句影响的行数
$query = $dbh->prepare("SELECT * FROM table_name");
$query->execute();
$count =$query->rowCount();
echo $count;
将查询结果放在一个数组中,您可以在其中执行计数($array)并在之后使用查询结果行?例:
$sc='SELECT * FROM comments';
$res=array();
foreach($db->query($sc) as $row){
$res[]=$row;
}
echo "num rows: ".count($res);
echo "Select output:";
foreach($res as $row){ echo $row['comment'];}
这是另一个问题,被错误地提出,会产生很多可怕的解决方案,所有这些都使解决一个不存在的问题变得非常复杂。
对于任何数据库交互,极其简单明了的规则是
始终选择您唯一需要的数据。
从这个角度来看,问题是错误的,公认的答案是正确的。但其他提出的解决方案太糟糕了。
问题是"如何以错误的方式进行计数"。人们永远不应该直截了当地回答它,相反,唯一正确的答案是"永远不应该选择行来计算它们。相反,请始终要求数据库为您计算行数。 这个规则是如此明显,以至于不太可能看到这么多人试图打破它。
学习了这个规则后,我们会发现这是一个SQL问题,甚至与PDO无关。而且,如果问得当,从SQL的角度来看,答案会立即出现 - DISTINCT
。
$num = $db->query('SELECT count(distinct boele) FROM tbl WHERE oele = 2')->fetchColumn();
是这个特定问题的正确答案。
从上述规则的角度来看,开场海报自己的解决方案也是可以接受的,但总的来说效率会降低。
方法可以计算行数。
$query = "SELECT count(*) as total from table1";
$prepare = $link->prepare($query);
$prepare->execute();
$row = $prepare->fetch(PDO::FETCH_ASSOC);
echo $row['total']; // This will return you a number of rows.
或者第二种方式是
$query = "SELECT field1, field2 from table1";
$prepare = $link->prepare($query);
$prepare->execute();
$row = $prepare->fetch(PDO::FETCH_NUM);
echo $rows[0]; // This will return you a number of rows as well.