domingo, 30 de junio de 2013

Extensión MySQLi - Parte 2: Consultas de selección

En la anterior parte del tutorial hemos hablado de las consultas que no devuelven resultado almacenado en la base de datos; osea las consultas de creación, borrado, inserción y actualización. Pero además de estas, tenemos otro tipo de consultas muy importantes y son las encargadas de mostrar los datos almacenados en la base de datos.

Consultas que devuelven resultado

Este tipo de consultas ejecutarán una sentencia de tipo "SELECT" sobre la base de datos devolviendo un conjunto de resultados en caso de que la consulta sea correcta y haya resultados que mostrar. Y false en caso de error en dicha consulta.

A) Interfaz orientada a objetos

 $sql = "SELECT cliente.id as id, cliente.nombre as nombre, cliente.cantidad as cant, producto.nombre as producto FROM cliente LEFT JOIN producto ON cliente.id=producto.id";  
 $resultado = $mysqli->query($sql);  
 if($mysqli->errno) die($mysqli->error);  

Perfecto, ahora ya hemos ejecutado una consulta que nos va a devolver datos de la base de datos. Los resultados de la ejecución de dicha consulta los tenemos en $resultado. Así que veamos los tres métodos más comunes de mostrar los datos.

1. array mysqli_result::fetch_assoc ( void )

Con este método obtenemos los datos de una fila en un array asociativo donde el nombre de cada columna es el indice. Pero el resultado de la consulta ($resultado) puede contener numerosas filas. Por lo que tendremos que crear un bucle para ir accediendo a cada una de las filas del resultado.

 while($fila = $resultado -> fetch_assoc(){  
   echo "ID: ".$fila['id'] . ", Nombre:".$fila['nombre'] .  
      ", Cantidad:".$nombre['cant'] . ", producto:".$fila['producto']."<br/>";  
 }  

2. mixed mysqli_result::fetch_array ( [ int $tiporesultado = MYSQLI_BOTH ] )

Con este método obtenemos los datos de una fila como un array asociativo, numérico o ambos. Por lo tanto dependiendo del parámetro de entrada el resultado devuelto será distinto:

 print_r($resultado-&gt;fetch_array(MYSQLI_NUM));   
Salida:
 Array ( [0] =&gt; 1 [1] =&gt; jose [2] =&gt; prueba@ejemplo.com )  


 print_r($resultado-&gt;fetch_array(MYSQLI_ASSOC));   
Salida:
  Array ( [id] =&gt; 1 [nombre] =&gt; jose [email] =&gt; prueba@ejemplo.com )   


 print_r($resultado->fetch_array()); //por defecto MYSQLI_BOTH  
Salida:
 Array  
 (  
   [0] => 1  
   [id] => 1  
   [1] => jose  
   [nombre] => jose  
   [2] => prueba@ejemplo.com  
   [email] => prueba@ejemplo.com  
 )  

Podemos acceder al array tanto indicando el indice númerico o el nombre de la columna.
Nuevamente si queremos obtener todas las filas de resultado de la consulta tendremos que iterar.

 while($fila = $resultado -&gt; fetch_array(MYSQLI_ASSOC){   
   echo "ID: ".$fila['id'] . ", Nombre:".$fila['nombre'] .   
    ", Cantidad:".$nombre['cant'] . ", producto:".$fila['producto']."&lt;br/&gt;";   
  }   

3. object mysqli_result::fetch_object ([ string $nombre_clase [, array $params ]])

Este método devuelve una fila de resultados como si fuese un objeto. Donde $nombre_clase es el nombre de la clase a instanciar (opcional). Y $params es un array opcional de parámetros a pasar al constructor de dicha clase.

 if ($resultado = $mysqli->query($query)) {  
   while ($objeto = $resultado->fetch_object()) {  
     echo $obj->nombre . "," . $obj->email . "<br/>";  
   }  
 }  

La potencia de este método viene al instanciar una clase. Ya que pasaremos los datos de la fila a un objeto y así podemos llamar a métodos de la clase instanciada para trabajar con ellos. Los campos de la fila del conjunto resultado se agregan automáticamente como atributos públicos de la clase. Por lo tanto podremos acceder a ellos dentro de la clase, sin tenerlos que definir.

 class prueba {  
   function mostrar(){  
     return "<br/>" . $this->id . ", " . $this->nombre . ", " . $this->email . "<br/>";  
   }  
 }  
 $mysqli = new mysqli('localhost','root','','mvc');  
 $resultado = $mysqli->query("SELECT id , nombre, email FROM usuario");  
 while ($fila = $resultado->fetch_object("prueba")){  
   echo $fila->mostrar();  
 }  

En este ejemplo no tenemos constructor. Si quisiéramos constructor y que a este se le pudieran pasar parámetros  se los pasaríamos como un array. Con la siguiente sintaxis: fetch_object("prueba",array( ... )).

B) Interfaz procedimental

Veamos la adaptación procedimental de los ejemplos del apartado anterior

 $con = mysqli_connect(...);  
 $sql = 'SELECT cliente.id as id, cliente.nombre as nombre, cliente.cantidad as cant, producto.nombre as producto FROM cliente LEFT JOIN producto ON cliente.id=producto.id';   
 $resultado = mysqli_query($con, $sql);   
 if($mysqli_errno($con)) die($mysqli_error($con));   

1. array mysqli_fetch_assoc ( mysqli_result $result )

Al igual que el método presentado en la interfaz orientada a objetos obtendremos un array asociativo que representará una fila del resultado. Por lo que tendremos que iterar para recorrer todas las filas de dicho resultado. Es importante recordar que el parámetro de entrada es el resultado de un mysqli_query() y no una conexión.

  while($fila = mysqli_fetch_assoc($resultado){   
   echo "ID: " . $fila['id'] . ", Nombre:".$fila['nombre'] .   
    ", Cantidad:".$nombre['cant'] . ", producto:".$fila['producto']."<br/>";   
  }   

2.  mixed mysqli_fetch_array ( mysqli_result $result [, int $tiporesultado = MYSQLI_BOTH ] )

MYSQLI_BOTH  - o si no si no especificamos nada, nos devolverá un array mixto de indices numéricos y claves. Dichas claves serán los nombres de las columnas de la consulta.
MYSQLI_ASSOC - nos devolverá un array asociativo. Al igual que antes, el nombre de las columnas serán las claves del array.
MYSQLI_NUM - nos devolverá un array numérico  Cada indice representará el contenido de cada columna de la consulta. Los indices tendrán el mismo orden que el especificado en la consulta "SELECT".

Al igual que en todos los método presentados, si no iteramos, solo obtendremos el array que representa a la primera fila del conjunto de resultados.

  while($fila = mysqli_fetch_array($resultado, MYSQLI_ASSOC){   
   echo "ID: " . $fila['id'] . ", Nombre:".$fila['nombre'] .   
    ", Cantidad:".$nombre['cant'] . ", producto:".$fila['producto']."<br/>";   
  }   

3.  object mysqli_fetch_object ( mysqli_result $result [, string $class_name [, array $params ]] )

Resulta un poco paradójico estar utilizando la interfaz procedimental de MySQLi y querer obtener el resultado de una fila de la consulta en formato de objeto. Pero también se puede hacer. Y al igual que con la interfaz orientada a objetos podemos indicar la clase que queremos instanciar y las opciones que le pasaremos al constructor de dicha clase.

 if ($resultado = mysqli_query($con,$query)) {   
   while ($objeto = mysqli_fetch_object($resultado)) {   
    echo $obj->nombre . "," . $obj->email . "<br/>";   
   }   
  }   

En este  artículo podemos ver una comparativa entre los tres métodos mencionados. Su conclusión es que fetch_assoc() consume menos recursos que las demás alternativas. Aunque tendrá un rendimiento similar fetch_array() si especificamos que tipo de array queremos que nos devuelva. Así evitamos duplicación de datos.

affected_rows y num_rows

En la parte 1 tutorial mostramos la propiedad affected_rows y su equivalente, si usamos interfaz procedimental, mysqli_affected_rows(). Resultando muy útil para saber cuantas filas han sido afectadas por la última consulta de modificación (insert, update, y delete). Lo cual nos puede dar información del éxito de la consulta. Ya que puede haberse ejecutado sin error pero sin el resultado esperado.

 $mysqli = new mysqli("localhost", "mi_usuario", "mi_contraseña", "demo");  
 if($mysqli->connect_errno) die($mysqli->connect_error);   
 $mysqli->query("DELETE FROM usuario where id = '1'");  
 if($mysqli->affected_rows == 0){  
   //no borrado  
 }  


Para las consultas de selección también tenemos una función que nos proporcionará el número de filas que contiene el resultado de la consulta. Que nos podría resultar útil, por ejemplo, en las las consultas en las que queremos averiguar si existe el usuario y password. Y esta función nos devolvería 1 fila en caso de que exista

A) Interfaz orientada a objetos

 $mysqli = new mysqli("localhost", "mi_usuario", "mi_contraseña", "demo");  
 if($mysqli->connect_errno) die($mysqli->connect_error);   
 $res = $mysqli->query("SELECT * FROM usuario WHERE name = 'prueba' AND pass = '1234' ");  
 if($res->num_rows == 0){  
   //no encontrado  
 }  

B) Interfaz procedimental

  $con = mysqli_connect("localhost", "mi_usuario", "mi_contraseña", "demo");   
  if(mysqli_connect_errno()) die(mysqli_connect_error());    
  $res = mysqli_query($con,"SELECT * FROM usuario WHERE nombreUsuario = 'prueba' and pass= '1234'");   
  if (mysqli_num_rows($res) == 0) {  
   //no encontrado  
  }   


Entradas relacionadas

Extensión MySQLi - Parte 1: Consultas de modificación
Extensión MySQLi - Parte 3: Consultas preparadas y escapado
Extensión MySQLi - Parte 4: Transacciones

1 comentario:

  1. En la parte:

    1. array mysqli_fetch_assoc ( mysqli_result $result )

    le falta un cierre de parentesis al while :D eso

    ResponderEliminar