Как получить общее количество строк запроса GROUP BY?

Из руководства PDO:

PDOStatement :: rowCount () возвращает количество строк, затронутых последним оператором DELETE, INSERT или UPDATE, выполняемым соответствующим объектом PDOStatement.

Если последний оператор SQL, выполняемый связанным с ним PDOStatement, был оператором SELECT , некоторые базы данных могут возвращать количество строк, возвращаемых этим оператором . Однако это поведение не гарантируется для всех баз данных и не должно полагаться на переносные приложения.

Я нашел это совсем недавно. Я только что изменил уровень абстракции db, чтобы не использовать SELECT COUNT(1) ... больше, потому что просто запрос фактических строк, а затем подсчет результата будет намного более эффективным. И теперь PDO не поддерживает это !?

Я не использую PDO для MySQL и PgSQL, но я делаю это для SQLite. Есть ли способ (без полного изменения dbal back) для подсчета строк, подобных этому в 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. Моим первоначальным решением было расширить метод SQLResult-> count (мой собственный), чтобы заменить SELECT ... FROM на SELECT COUNT(1) 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 back) для подсчета строк, подобных этому в PDO?

В соответствии с этим комментарием проблема SQLite была введена изменением API в 3.x.

Тем не менее, вы можете проверить, как PDO фактически реализует функциональные возможности перед его использованием.

Я не знаком с его внутренними компонентами, но я бы с подозрением относился к идее, что PDO анализирует ваш SQL (поскольку синтаксическая ошибка SQL появится в журналах БД), не говоря уже о том, чтобы попытаться сделать хоть малейшее ощущение, чтобы подсчитывать строки используя оптимальную стратегию.

Предполагая, что это не так, реалистичные стратегии для возврата количества всех применимых строк в выражении select включают в себя строковое манипулирование предложением limit из вашего оператора SQL и любой из следующих:

  1. Выполнение select count () в качестве подзапроса (таким образом, чтобы избежать проблемы, описанной в PS);
  2. Открытие курсора, запуск fetch all и подсчет строк; или
  3. Открыв такой курсор в первую очередь и аналогичным образом подсчитывая оставшиеся строки.

Однако гораздо лучший способ подсчета – выполнить полностью оптимизированный запрос, который сделает это. Чаще всего это означает переписывание значимых фрагментов исходного запроса, который вы пытаетесь разбивать на страницы, – удаление ненужных полей и порядок операций и т. Д.

Наконец, если ваши наборы данных достаточно велики, что учитывает любые задержки, вы также можете исследовать возвращаемую оценку, полученную из статистики , и / или периодически кэшировать результат в 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; 

Как насчет ввода результатов запроса в массив, где вы можете сделать подсчет (массив $) и использовать последующие строки запроса после? Пример:

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