3.6 Consultas a bases de datos
Introducción
Las consultas SQL son una de las operaciones más comunes cuando trabajamos con bases de datos. Mediante las consultas SELECT, podemos recuperar datos de las tablas de la base de datos, lo que nos permite mostrar, analizar y manipular los datos según las necesidades de la aplicación.
En esta sección, nos centraremos en las consultas SELECT básicas y cómo podemos utilizarlas en PHP para interactuar con bases de datos. A medida que avanzamos, veremos cómo filtrar y ordenar los resultados de las consultas utilizando cláusulas como WHERE y ORDER BY.
Las consultas SELECT permiten extraer datos de una tabla y trabajar con ellos en nuestro código. Es fundamental aprender cómo filtrar los resultados utilizando la cláusula WHERE, cómo ordenar los resultados con ORDER BY, y cómo usar operadores comunes como AND, OR, IN y BETWEEN.
3.4.1 Consultas SELECT básicas
La instrucción SELECT es la más utilizada en SQL para obtener datos de una base de datos. Es importante entender cómo estructurarla de manera eficiente para obtener solo los datos necesarios, lo que mejora el rendimiento de la consulta.
Sintaxis básica de un SELECT:
SELECT columna1, columna2, ...
FROM nombre_de_tabla;
SELECT: Especifica las columnas que queremos seleccionar.FROM: Indica la tabla de la que vamos a obtener los datos.
Ejemplo de consulta básica:
Vamos a hacer una consulta básica a la tabla employees de la base de datos employees para obtener los nombres y apellidos de los empleados.
Ejemplo de consulta básica con MySQLi (orientado a objetos):
En este ejemplo vamos a realizar una consulta para edtraer los id, nombres y apellidos de los empleados de la tabla employees utilizando MySQLi.
Ejemplo de consulta básica
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Vamos a analizar el código y cer qué realiza cada método o función. Lo hacemos para la version orientada a objetos de MySQLi, la procedimental es similar.
- Crear conexión: Se establece una conexión a la base de datos utilizando
new mysqli(), donde se especifican el host, el usuario, la contraseña y el nombre de la base de datos. - Comprobar conexión: Se verifica si la conexión fue exitosa. Si no, se muestra un mensaje de error y se detiene la ejecución del script.
- Consulta: Se define la consulta SQL que queremos ejecutar. En este caso, seleccionamos los campos
emp_no,first_nameylast_namede la tablaemployees. En este caso la consulta no tiene parámetros, más adelante veremos cómo pasarlos. - Ejecutar consulta: Se ejecuta la consulta utilizando
$conexion->query($query), que devuelve un objeto de resultado$resultado. - Mostrar resultados: Se itera sobre los resultados utilizando un bucle
while, y se accede a cada fila de resultados con$fila = $resultado->fetch_assoc(). Luego, se muestran los nombres y apellidos de los empleados. Cada vez que llamamos afetch_assoc(), obtenemos una fila de resultados en forma de array asociativo, y pasamos a el objeto $resultado apunta a la siguiente fila. Cuando no hay más filas,fetch_assoc()devuelvefalsey el bucle se detiene. Otra opciones:fetch_row(): Devuelve un array numérico.fetch_array(): Devuelve un array asociativo y numérico.fetch_object(): Devuelve un objeto con propiedades que corresponden a los nombres de las columnas.
- Cerrar conexión: Finalmente, se cierra la conexión a la base de datos utilizando
$conexion->close().
Visto de esta manera, es como si para cada consulta objetenmos un array de registros. Donde cada elemento del array es una registro (fila) de la consulta. Podemos acceder a cada campo del registro como si fuera un elemento del array, utilizando el nombre de la columna como índice.
Ejemplo de consulta básica con PDO:
Ejemplo de consulta básica con PDO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
En este ejemplo, utilizamos PDO para conectarnos a la base de datos y realizar la consulta. La estructura es similar a la de MySQLi, pero con algunas diferencias en la forma de manejar la conexión y los errores.
- Crear conexión: Se establece una conexión a la base de datos utilizando
new PDO(), donde se especifican el DSN (Data Source Name), el usuario y la contraseña. - Comprobar conexión: Se utiliza un bloque
try-catchpara manejar excepciones. Si la conexión falla, se lanza una excepción y se muestra un mensaje de error. - Consulta: Se define la consulta SQL que queremos ejecutar. En este caso, seleccionamos los campos
first_nameylast_namede la tablaemployees. - Ejecutar consulta: Se ejecuta la consulta utilizando
$conexion->query($query), que devuelve un objeto de resultado$resultado. - Mostrar resultados: Se itera sobre los resultados utilizando un bucle
while, y se accede a cada fila de resultados con$fila = $resultado->fetch(PDO::FETCH_ASSOC). Luego, se muestran los nombres y apellidos de los empleados. Otras opciones defetch()permiten obtener los resultados en diferentes formatos:PDO::FETCH_ASSOC: Devuelve un array asociativo.PDO::FETCH_NUM: Devuelve un array numérico.PDO::FETCH_BOTH: Devuelve un array asociativo y numérico (por defecto).
- Cerrar conexión: Finalmente, se cierra la conexión a la base de datos estableciendo
$conexionanull.
Filtrar resultados con WHERE
El WHERE se utiliza para filtrar los resultados y obtener solo aquellos que cumplan una condición específica. Esto es útil cuando necesitas recuperar datos que cumplen ciertos criterios.
Sintaxis de WHERE:
SELECT columna1, columna2, ...
FROM nombre_de_tabla
WHERE condicion;
Ejemplo de consulta con WHERE:
Queremos obtener los empleados que tiene el id 5000.
<?php
$query = "SELECT emp_no, first_name, last_name, salary FROM employees WHERE emp_no = 5000";
Ejemplo con MySQLi (orientado a objetos):
Ejemplo con WHERE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
En este ejemplo, utilizamos una consulta preparada para evitar inyecciones SQL. La consulta se prepara con un marcador de posición ?, y luego se vincula el valor del parámetro utilizando bind_param().
Ejemplo con PDO:
Ejemplo de WHERE en PDO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
En este ejemplo, utilizamos un marcador de posición :emp_no en la consulta y vinculamos el valor utilizando bindParam(). Esto ayuda a prevenir inyecciones SQL y mejora la seguridad de la aplicación.
Resumen de la sección 3.4.1
- Hemos cubierto la sintaxis básica de una consulta
SELECT. - Hemos aprendido a filtrar resultados utilizando la cláusula
WHERE. - Se presentaron ejemplos con MySQLi (procedimental y orientado a objetos) y PDO.
- Los ejercicios prácticos permitirán a los estudiantes practicar consultas básicas y filtrado de datos.
Ejercicios prácticos:
Estos ejercicios debes solucionarlos con MySQLi (OO) y PDO. Puedes elegir el que prefieras, pero es recomendable que practiques ambos. Recuerda que puedes utilizar la base de datos employees para realizar las consultas.
- Ejercicio 1: Crea un formulario que permita al usuario ingresar un
emp_noy muestre el nombre y apellido del empleado correspondiente.- Pista: Utiliza una consulta preparada para evitar inyecciones SQL.
- Ejemplo de consulta:
SELECT first_name, last_name FROM employees WHERE emp_no = ?
- Ejercicio 2: Crea un formulario que pida el nombre de un empleado y muestre todos los empleados que contengan ese nombre en su
first_nameo en sulast_name.- Pista: Utiliza el operador
LIKEpara buscar coincidencias parciales. - Ejemplo de consulta:
SELECT first_name, last_name FROM employees WHERE first_name LIKE '%nombre%'
- Pista: Utiliza el operador
- Ejercicio 3: Crea un formulario que permita al usuario ingresar un rango de fechas y muestre todos los empleados contratados dentro de ese rango.
- Pista: Utiliza la cláusula
BETWEENpara filtrar por fechas. - Ejemplo de consulta:
SELECT first_name, last_name FROM employees WHERE hire_date BETWEEN 'fecha_inicio' AND 'fecha_fin'
- Pista: Utiliza la cláusula
3.4.2 Consultas complejas
Uso de JOIN para relaciones entre tablas
Las consultas complejas son aquellas que involucran múltiples tablas y relaciones entre ellas. En este caso, utilizamos JOIN para combinar datos de diferentes tablas en una sola consulta. Aunque no es un asunto a tratar en este módulo, decir, que las cosultas multiplataforma de pueden realizar básicamente de dos maneras:
- FROM Se especifican las tablas necesarias separadas por comas, luego en el
WHEREse especifican las condiciones de unión (normalmente las claves ajenas). - JOIN Se especifican las tablas necesarias y se utilizan las cláusulas
JOIN, para definir cómo se deben unir las tablas.- INNER JOIN: Devuelve solo las filas que tienen coincidencias en ambas tablas.
- LEFT JOIN: Devuelve todas las filas de la tabla izquierda y las filas coincidentes de la tabla derecha. Si no hay coincidencia, se devuelven valores nulos para la tabla derecha.
- RIGHT JOIN: Devuelve todas las filas de la tabla derecha y las filas coincidentes de la tabla izquierda. Si no hay coincidencia, se devuelven valores nulos para la tabla izquierda.
Ejemplo de INNER JOIN con MySQLi utilizando parámetros:
En este ejmplo vamos a realizar una consulta que une varias tablas para obtener información relacionada. Vamos a obtener el nombre y apellido de los empleados junto con el nombre de su departamento. Parametrizaremos la consulta para que el usuario pueda filtrar por un dept_no específico.
Ejemplo de INNER JOIN - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
En este ejemplo, aunque l la consulta es más compleja, la estructura es similar a la de una consulta básica. La diferencia principal es que estamos utilizando INNER JOIN para combinar datos de varias tablas.
INNER JOIN: Se utiliza para combinar filas de dos o más tablas basadas en una condición de coincidencia. En este caso, estamos uniendo la tablaemployeescondept_empydepartmentspara obtener información relacionada.ON: Especifica la condición de coincidencia entre las tablas. En este caso, estamos uniendoemployees.emp_nocondept_emp.emp_noydept_emp.dept_nocondepartments.dept_no. Normalmente se utilizan las claves ajenas para unir las tablas.WHERE: Se utiliza para filtrar los resultados según una condición específica. En este caso, estamos filtrando pordepartments.dept_no.?: Es un marcador de posición que se utiliza en consultas preparadas. Se reemplaza por el valor del parámetro al ejecutar la consulta.
Ejemplo de INNER JOIN con PDO utilizando parámetros:
Ejemplo de INNER JOIN con PDO - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
La explicación es similar a la de MySQLi. La diferencia principal es que estamos utilizando bindParam() para vincular el parámetro :dept_no a la consulta.
prepare(): Prepara la consulta SQL para su ejecución. Esto ayuda a prevenir inyecciones SQL al separar la consulta de los datos.bindParam(): Se utiliza para vincular un parámetro a una variable. En este caso, estamos vinculando el parámetro:dept_noa la variable$departamento_id, que contiene el valor del departamento que queremos filtrar.PDO::PARAM_INT: Especifica que el parámetro es un entero. Esto ayuda a PDO a manejar el tipo de dato correctamente. Otros tipos de parámetros:PDO::PARAM_STR: Especifica que el parámetro es una cadena.PDO::PARAM_BOOL: Especifica que el parámetro es un booleano.PDO::PARAM_NULL: Especifica que el parámetro es nulo.PDO::PARAM_LOB: Especifica que el parámetro es un objeto LOB (Large Object), como un archivo o una imagen.
bindValue(): Se utiliza para vincular un valor a un parámetro. En este caso, estamos vinculando el parámetro:dept_noal valor de$departamento_id. La diferencia es quebindParam()vincula la variable por referencia, mientras quebindValue()vincula el valor directamente.
Uso de LEFT JOIN
Ejemplo de LEFT JOIN con MySQLi (orientado a objetos) utilizando parámetros:
Ejemplo de LEFT JOIN con MySQLi - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
En este ejemplo, utilizamos LEFT JOIN para obtener todos los empleados, incluso aquellos que no están asignados a un departamento. Esto es útil cuando queremos mostrar todos los empleados, independientemente de si tienen un departamento asociado o no.
Ejemplo de LEFT JOIN con PDO utilizando parámetros:
Ejemplo de LEFT JOIN con PDO - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Uso de GROUP BY y HAVING
Ejemplo de GROUP BY con MySQLi utilizando parámetros:
Ejemplo de GROUP BY con MySQLi - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
En este ejemplo, utilizamos GROUP BY para agrupar los resultados por departamento y HAVING para filtrar los grupos que tienen más de un cierto número de empleados. Esto es útil cuando queremos obtener estadísticas o resúmenes de datos.
GROUP BY: Se utiliza para agrupar filas que tienen valores idénticos en columnas específicas. En este caso, estamos agrupando pordepartments.dept_name.COUNT(*): Se utiliza para contar el número de filas en cada grupo. En este caso, estamos contando el número de empleados en cada departamento.HAVING: Se utiliza para filtrar los grupos después de que se han creado. En este caso, estamos filtrando los grupos que tienen más de un cierto número de empleados.?: Es un marcador de posición que se utiliza en consultas preparadas. Se reemplaza por el valor del parámetro al ejecutar la consulta.
Ejemplo de GROUP BY con PDO utilizando parámetros:
Ejemplo de GROUP BY con PDO - Parametrizado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Resumen de la sección 3.4.2
En este punto, hemos cubierto cómo realizar consultas complejas utilizando JOINs para combinar datos de múltiples tablas y GROUP BY y HAVING para agrupar y filtrar los resultados. También hemos aprendido cómo parametrizar estas consultas para mejorar la seguridad y evitar SQL Injection.
Ejercicios prácticos:
- Ejercicio 1: Realiza una consulta parametrizada que muestre el nombre de los empleados en activo junto con el nombre de su departamento, filtrado por un
dept_noespecífico. Los empleados que están en activo deben tener el campoto_dateen la tabladept_empcomo9999-01-01. - Ejercicio 2: Realiza una consulta parametrizada utilizando
LEFT JOINpara mostrar todos los departamentos y el número de empleados en cada uno. Si un departamento no tiene empleados, debe mostrarse con un conteo de 0. - Ejercicio 3: Realiza una consulta parametrizada que cuente cuántos empleados hay en cada departamento, mostrando solo aquellos con más de 5 empleados.
- Ejercicio 4: Realiza una consulta parametrizada con
GROUP BYyHAVINGpara mostrar los departamentos con más de 10 empleados.
3.4.3 Ejemplos prácticos
Ejemplo 1: Mostrar todos los empleados de un departamento
En este ejemplo, vamos a realizar una consulta que muestre todos los empleados de un departamento específico. Utilizaremos un INNER JOIN para combinar la información de la tabla employees y departments.
Ejemplo de código con MySQLi (orientado a objetos):
Ejemplo 1: Mostrar empleados de un departamento
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Ejemplo 2: Ordenar empleados por salario
En este ejemplo, vamos a ordenar a los empleados por su salario. Utilizaremos la cláusula ORDER BY para ordenar los resultados de la consulta.
Ejemplo 2: Ordenar empleados por salario
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
<?php
try {
$conexion = new PDO("mysql:host=localhost;dbname=employees", "root", "");
$conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Consulta con ORDER BY
$query = "SELECT first_name, last_name, salary FROM employees
ORDER BY salary DESC";
$stmt = $conexion->query($query);
while ($fila = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "Nombre: " . $fila['first_name'] . " - Apellido: " . $fila['last_name'] . " - Salario: " . $fila['salary'] . "<br>";
}
} catch (PDOException $e) {
echo "Conexión fallida: " . $e->getMessage();
}
$conexion = null;
?>
Ejemplo 3: Filtrar empleados por fecha de contratación
En este ejemplo, vamos a mostrar los empleados contratados después de una fecha específica utilizando la cláusula WHERE.
Ejemplo de código con MySQLi (orientado a objetos):
Ejemplo 3: Filtrar empleados por fecha de contratación
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
En este ejemplo, utilizamos la cláusula WHERE para filtrar los empleados contratados después de una fecha específica. La consulta se parametriza para evitar inyecciones SQL.
- hire_date: Es la columna que contiene la fecha de contratación de los empleados.
Resumen de la sección 3.4.3
En este punto, hemos cubierto ejemplos prácticos de consultas SELECT que incluyen:
- Obtener todos los empleados de un departamento.
- Ordenar los empleados por salario.
- Filtrar empleados por fecha de contratación.
Cada ejemplo utiliza consultas parametrizadas para garantizar la seguridad y evitar problemas como SQL Injection.
Ejercicios prácticos:
Para este ejercicio trata de crear un fichero php que contenga todas las funciones que necesitarás pera resolver el ejercicio. De esta manera en el fichero php que contenga la vista (HTML) solo tendrás que incluir el fichero de funciones y llamar a las funciones necesarias. Para incluir el fichero de funciones puedes utilizar la función include o require de PHP.
include: Este comando se utiliza para incluir el contenido de un archivo en otro archivo PHP. Si el archivo no se encuentra, se mostrará una advertencia, pero elscriptcontinuará ejecutándose.require: Este comando también se utiliza para incluir el contenido de un archivo en otro archivo PHP. Sin embargo, si el archivo no se encuentra, se generará un error fatal y elscriptse detendrá.
Ejemplo de uso:
1 2 3 4 | |
- Crea un formulario que permita al usuario elegir un departamento y una fecha de contratación.
- Muestra todos los empleados de ese departamento que fueron contratados después de la fecha seleccionada y que estén activos.
- Muestra también el nombre del responsable actual del departamento.
- Discursión: En este ejercicio debes realizar diferentes consultas, podemos plantearnos utilizar una única conexión para todas las consultas o crear una conexión para cada consulta. ¿Qué ventajas e inconvenientes tiene cada opción? ¿Qué harías tú?