如何获得按列分组的行数?

从PDO手册:

PDOStatement :: rowCount()返回由相应PDOStatement对象执行的最后一个DELETE,INSERT或UPDATE语句影响的行数

如果由关联的PDOStatement执行的最后一条SQL语句是SELECT语句,则某些数据库可能会返回该语句返回的行数 。 但是,这种行为不能保证所有的数据库 ,不应该依赖便携式应用程序。

我最近才发现。 我只是改变了我的数据库抽象层不使用SELECT COUNT(1) ...因为只是查询实际的行,然后计算结果会更有效率。 现在PDO不支持!

我不使用PDO的MySQL和Pg​​SQL,但我做的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都不是!

PS。 我最初的解决scheme是扩展SQLResult->计数方法(我自己的),以取代SELECT ... FROM通过SELECT COUNT(1) FROM ,只是返回该数字(非常低效,但只适用于SQLite PDO)。 这还不够好,因为在上面的查询中是一个GROUP BY ,它会改变COUNT(1)的含义/function。

这里有两个解决scheme给你

准备:

 $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]; 

使用查询:

 $sql="SELECT count(*) FROM [tablename] WHERE key == '$key' "; $result = $this->db->query($sql); $row = $result->fetch(PDO::FETCH_NUM); echo $row[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和Pg​​SQL,但我做的SQLite。 有没有一种方法(没有完全改变dbal回来)在PDO中计算这样的行?

根据这个评论 ,SQLite问题是由3.x中的API更改引入的。

也就是说,您可能想要在使用PDO之前检查PDO是如何实际实现的。

我不熟悉它的内部,但我会怀疑PDOparsing你的SQL(因为SQL语法错误会出现在数据库的日志中),更不用说为了计算行采用最佳策略。

假设它并不确实,它返回select语句中所有适用行的计数的实际策略包括string操作SQL语句中的限制子句,以及以下任一操作:

  1. 运行一个select count()作为子查询(从而避免你在PS中描述的问题);
  2. 打开游标,运行全部提取并计数行; 要么
  3. 首先打开了这样的游标,并且类似地计算剩余的行。

然而,更好的方法是执行完全优化的查询。 通常情况下,这意味着要重写您正在尝试分页的初始查询的有意义的块 – 剥离不需要的字段和按操作sorting等。

最后,如果您的数据集足够大,可以计算出任何滞后时间,您可能还需要调查返回从统计数据导出的估计值,和/或定期将结果caching到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。 说,这样的事情:(警告,代码未经testing)

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

这又是另外一个问题,错误地提出了许多可怕的解决办法,这些都使解决一个不存在的问题变得非常复杂。

任何数据库交互的极其简单和明显的规则是

始终select您需要的唯一数据。

从这个angular度来看,这个问题是错误的,被接受的答案是正确的。 但其他提出的解决scheme只是可怕的。

问题是“如何计错方式”。 一个人不应该直接回答,而是唯一正确的答案是“永远不要select行来计算它们,而是总是要求数据库为你计算行数”。 这个规则是如此明显,看到这么多尝试打破它是不可能的。

在学习了这条规则之后,我们会看到这是一个SQL问题 ,甚至不涉及PDO。 而且,如果从SQL的angular度来看问题得到了恰当的解答,问题的答案会立即出现 – DISTINCT

 $num = $db->query('SELECT count(distinct boele) FROM tbl WHERE oele = 2')->fetchColumn(); 

是这个特定问题的正确答案。

开头张贴自己的解决scheme也是从上述规则的angular度来看是可以接受的,但总的来说效率不高。

有两种方法可以计算行数。

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