php - ejemplos - no repetir registros en consulta sql
¿Cómo obtener el número total de filas de una consulta GROUP BY? (11)
No uso PDO para MySQL y PgSQL, pero sí para SQLite. ¿Hay alguna manera (sin cambiar por completo el respaldo dbal) de contar filas como esta en PDO?
De acuerdo con este comentario , el problema de SQLite fue introducido por un cambio de API en 3.x.
Dicho esto, es posible que desee inspeccionar cómo PDO realmente implementa la funcionalidad antes de usarla.
No estoy familiarizado con sus aspectos internos, pero sospecho que PDO analiza su SQL (ya que un error de sintaxis SQL aparecería en los registros de la base de datos) y mucho menos intenta tener el menor sentido de ello para contar las filas usando una estrategia óptima.
Suponiendo que no lo haga, las estrategias realistas para devolver un recuento de todas las filas aplicables en una instrucción select incluyen la manipulación de cadena de la cláusula límite de su instrucción SQL, y cualquiera de:
- Ejecutando un conteo select () en él como una subconsulta (evitando así el problema que describió en su PS);
- Abrir un cursor, ejecutar buscar todo y contar las filas; o
- Después de abrir dicho cursor en primer lugar, y contar de manera similar las filas restantes.
Una forma mucho mejor de contar, sin embargo, sería ejecutar la consulta totalmente optimizada que lo hará. En la mayoría de los casos, esto significa reescribir los fragmentos significativos de la consulta inicial que está intentando paginar: eliminar los campos innecesarios y ordenarlos por operaciones, etc.
Por último, si los conjuntos de datos son lo suficientemente grandes como para contar cualquier tipo de retraso, es posible que también desee investigar la devolución de la estimación derivada de las statistics y / o el almacenamiento en caché periódico del resultado en Memcache. En algún momento, tener conteos exactamente correctos ya no es útil ...
Del manual de PDO:
PDOStatement :: rowCount () devuelve el número de filas afectadas por la última instrucción DELETE, INSERT o UPDATE ejecutada por el objeto PDOStatement correspondiente.
Si la última instrucción SQL ejecutada por la PDOStatement asociada era una instrucción SELECT , algunas bases de datos pueden devolver el número de filas devueltas por esa instrucción . Sin embargo, este comportamiento no se garantiza para todas las bases de datos y no se debe confiar en las aplicaciones portátiles.
Lo descubrí solo muy recientemente. Acababa de cambiar mi capa de abstracción db para no usar SELECT COUNT(1) ...
ya que solo cuestionar las filas reales y luego contar el resultado sería mucho más eficiente. Y ahora PDO no es compatible con eso !?
No uso PDO para MySQL y PgSQL, pero sí para SQLite. ¿Hay alguna manera (sin cambiar por completo el respaldo dbal) de contar filas como esta en PDO? En MySQL, esto sería algo como esto:
$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
Con los controladores MySQLi y PgSQL, esto es posible. ¡Con todo PDO, no es así!
PD. Mi solución inicial fue extender el método SQLResult-> count (el mío) para reemplazar SELECT ... FROM
por SELECT COUNT(1) FROM
y simplemente devolver ese número (muy ineficiente, pero solo para SQLite PDO). Sin embargo, eso no es suficiente, porque en el ejemplo anterior, la consulta es un GROUP BY
, que cambiaría el significado / función de COUNT(1)
.
¿Qué hay de poner los resultados de la consulta en una matriz, donde puede hacer un recuento ($ array) y utilizar las filas resultantes de la consulta después? Ejemplo:
$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''];}
Aquí está la solución para ti
$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];
Debe usar rowCount: devuelve el número de filas afectadas por la última instrucción SQL
$query = $dbh->prepare("SELECT * FROM table_name");
$query->execute();
$count =$query->rowCount();
echo $count;
El método que terminé usando es muy simple:
$query = ''SELECT a, b, c FROM tbl WHERE oele = 2 GROUP BY boele'';
$nrows = $db->query("SELECT COUNT(1) FROM ($query) x")->fetchColumn();
Puede que no sea el más eficiente, pero parece ser infalible, porque realmente cuenta los resultados de la consulta original.
Es un poco ineficaz para la memoria, pero si usa los datos de todos modos, lo uso con frecuencia:
$rows = $q->fetchAll();
$num_rows = count($rows);
Esa es otra pregunta que, erróneamente, genera MUCHAS soluciones terribles, todas complicadas para resolver un problema inexistente.
La regla extremadamente simple y obvia para cualquier interacción con la base de datos es
Seleccione siempre la única información que necesita.
Desde este punto de vista, la pregunta es incorrecta y la respuesta aceptada es correcta. Pero otras soluciones propuestas son simplemente terribles.
La pregunta es "cómo hacer que el recuento sea incorrecto". Nunca se debe responder de manera sencilla, sino que la única respuesta correcta es "Nunca se deben seleccionar las filas para contarlas. En cambio, SIEMPRE solicite a la base de datos que cuente las filas por usted". Esta regla es tan obvia, que es improbable ver tantos intentos de romperla.
Después de aprender esta regla, veríamos que esta es una pregunta de SQL , ni siquiera relacionada con PDO. Y, si se preguntara correctamente, desde la perspectiva de SQL, la respuesta aparecería en un instante: DISTINCT
.
$num = $db->query(''SELECT count(distinct boele) FROM tbl WHERE oele = 2'')->fetchColumn();
es la respuesta correcta a esta pregunta en particular.
La propia solución del afiche de apertura también es aceptable desde la perspectiva de la regla antes mencionada, pero sería menos eficiente en términos generales.
Hay dos formas de contar la cantidad de filas.
$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.
O la segunda forma es
$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.
Si está dispuesto a renunciar a una idea de abstracción, entonces podría usar una clase contenedora personalizada que simplemente transfiera todo al PDO. Digamos algo como esto: (Advertencia, código no probado)
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 );
}
}
Tal vez esto hará el truco para ti?
$FoundRows = $DataObject->query(''SELECT FOUND_ROWS() AS Count'')->fetchColumn();
Tenga en cuenta que una PDOStatement
es Traversable
. Dada una consulta:
$query = $dbh->query(''
SELECT
*
FROM
test
'');
Se puede repetir sobre:
$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>'';
}
O puedes hacer algo como esto:
$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>'';
}