如何获得按列分组的行数?
从PDO手册:
PDOStatement :: rowCount()返回由相应PDOStatement对象执行的最后一个DELETE,INSERT或UPDATE语句影响的行数 。
如果由关联的PDOStatement执行的最后一条SQL语句是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都不是!
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和PgSQL,但我做的SQLite。 有没有一种方法(没有完全改变dbal回来)在PDO中计算这样的行?
根据这个评论 ,SQLite问题是由3.x中的API更改引入的。
也就是说,您可能想要在使用PDO之前检查PDO是如何实际实现的。
我不熟悉它的内部,但我会怀疑PDOparsing你的SQL(因为SQL语法错误会出现在数据库的日志中),更不用说为了计算行采用最佳策略。
假设它并不确实,它返回select语句中所有适用行的计数的实际策略包括string操作SQL语句中的限制子句,以及以下任一操作:
- 运行一个select count()作为子查询(从而避免你在PS中描述的问题);
- 打开游标,运行全部提取并计数行; 要么
- 首先打开了这样的游标,并且类似地计算剩余的行。
然而,更好的方法是执行完全优化的查询。 通常情况下,这意味着要重写您正在尝试分页的初始查询的有意义的块 – 剥离不需要的字段和按操作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.