En posts anteriores hemos aprendido a definir la estructura de la base de datos y a cargar, borrar o actualizar, los datos en las tablas. Ahora toca aprender los comandos SQL para la recuperación de datos, las conocidas como consultas de selección, donde el comando SELECT resulta fundamental.

Sintaxis

La sintaxis básica para este tipo de consultas es:

SELECT [ALL | DISTINCT] <lista de campos> FROM <lista de tablas>

[WHERE ….]

[GROUP BY…]

[HAVING….]

[ORDER BY…]

Donde el significado de los distintos datos es:

  • SELECT: Se emplea para seleccionar los campos que quieren mostrarse en la consulta. Admite dos modificadores: ALL (por defecto) y DISTINCT.
    • ALL: Extrae todos los registros que cumplan las condiciones, aunque estén repetidos. No es necesario indicarlo porque es el valor por defecto.
    • DISTINCT: Omite los registros duplicados
  • <lista de campos>: listamos los campos que queremos aparezcan en la consulta, separados por comas.
    • “*” : Se puede emplear para seleccionar todos los campos.
    • Alias: podemos colocar un alias y dos puntos antes del nombre de cada campo y en la consulta aparecerá dicho alias como título de la columna en lugar del nombre original del campo que aparece en la tabla.
  • FROM: Indica las tablas o consultas de las que se extraen los datos.
  • <lista de tablas>: lista las tablas de las que se extraen los campos.
  • WHERE: se emplea para indicar las condiciones para la búsqueda.
  • GROUP BY: indica los campos por los que agrupamos los resultados de la consulta.
  • HAVING: Se emplea para definir las condiciones para los campos agrupados.
  • ORDER BY: Indica los campos por los que hay que ordenar el resultado de la consulta. Admite dos modificadores: ASC (por orden ascendente) y DESC (por orden descendente).

La relación entre las distintas tablas, se establece en la cláusula FROM que es la que nos indica las tablas de las que se extraen los datos. No olvidemos que estamos en una BBDD relacional, y que manejamos Tablas con relaciones entre ellas. Y la cláusula FROM dispone de una serie de operadores para  establecer las combinaciones entre tablas. Estos operadores son:

  • [LEFT | RIGTH | INNER] : se emplean para definir el tipo de combinación. La tabla donde se inicia la combinación es la que se indica a la izquierda, siendo la de la derecha donde se finaliza la combinación.

Siguiendo la propia descripción de Access:

  • LEFT: Incluye todos los registros de la tabla de la izquierda y solo aquellos registros de la tabla de la derecha donde los campos combinados sean iguales.
  • RIGTH: Incluye todos los registros de la tabla de la derecha y solo aquellos registros de la tabla de la izquierda donde los campos combinados sean iguales.
  • INNER: Incluye sólo las filas donde los campos combinados de ambas tablas sean iguales.

Para comprender el funcionamiento de todos estos comandos y aprender a emplearlos en consultas de selección, lo mejor es que practiquemos con ellos:

Recuperación de datos con SQL

Como ejemplo para practicar con los Comandos SQL para la recuperación de datos, usaré la BBDD Proveedores, la que generamos en un post anterior. Sencillamente tomamos esta BBDD porque, de los que hemos ido generando, es la que más datos tiene y mejor nos servirá para practicar las consultas de selección.

Paso 1: Los datos de partida

A modo de comprobación, los datos que tenemos en nuestras dos tablas de trabajo son:

las dos tablas de datos (Proveedores y Productos en proveedores) empleadas en el post

 Paso 2: Extrayendo los datos de un campo de una tabla

Sin duda la consulta de selección más sencilla que podemos realizar sería extraer los datos de un campo de una única tabla. Por ejemplo, obtener los nombres de nuestros proveedores. Para ello tendríamos que realizar la siguiente sentencia SQL:

SELECT NombreProveedor FROM Proveedores;

Después de la instrucción SELECT, indicamos el campo que queremos extraer, y después de FROM, la tabla donde se encuentra ese campo.

Si ejecutamos la consulta obtendremos los 5 valores del campo NombreProveedor en la Tabla Proveedores.

NombreProveedor es el campo que habíamos escogido para crear la relación entre las tablas Proveedores y ProductoEnProveedores, luego está en ambas tablas. Si ahora cambiamos la sentencia SQL diciéndole al gestor de la BBDD que busque los datos del campo NombreProveedor pero en la Tabla ProductoEnProveedores, obtendríamos 20 valores, esta vez con varias repeticiones, ya que el campo índice que no admite duplicados es el de la Tabla Proveedores.
La nueva sentencia SQL sería:

SELECT NombreProveedor FROM ProductosEnProveedores;

Paso 3: Extrayendo los datos de varios campos de una misma tabla

La sentencia SQL para extraer datos de varios campos es muy similar a la anterior, sencillamente tenemos que indicar todos los campos que queremos extraer, separados por comas. Por ejemplo, si quisiéramos extraer todos los campos de la tabla proveedores la instrucción sería:

SELECT NombreProveedor, ContactoProveedor , Telefono FROM Proveedores;

En este caso tenemos un atajo para realizar la consulta, en lugar de indicar todos los campos podemos utilizar el modificador ALL

SELECT ALL* FROM Proveedores;

Paso 4: Empleando el modificador DISTINCT

Empleando el modificador DISTINCT, omitimos los registros duplicados. Puesto que en la Tabla Proveedores no tenemos valores  duplicados, vamos a pasar a trabajar con la Tabla ProductosEnProveedores.

Si ejecutamos la ultima consulta que hicimos pero cambiando el modificador ALL por DISTINCT

SELECT DISTINCT* FROM ProductosEnProveedores;

Obtendremos 20 registros, todos los de la Tabla ProductosEnProveedores, ya que son todos distintos porque estamos considerando los valores de todos los campos. Sin embargo, si pasamos a indicar el campo NombreProveedor:

SELECT DISTINCT NombreProveedor FROM ProductosEnProveedores;

Ahora simplemente obtengo 5 resultados, los 5 proveedores que tengo.

Paso 5: Poniendo una condición

En las consultas de selección podemos filtrar los registros que recuperamos poniendo condiciones sobre los valores que estos contengan. Por ejemplo, si queremos saber que proveedores me suministran Naranjas, ejecutaríamos la siguiente sentencia SQL:

SELECT NombreProveedor, Producto FROM ProductosEnProveedores

WHERE (Producto=»Naranja»);

Obtenemos 5 Proveedores. La sentencia selecciona los campos NombreProveedor y Producto de la tabla ProductosEnProveedores, esto ya lo habíamos visto. Ahora, añadimos una clausula WHERE para poner una condición sobre los valores de uno de los campos, el campo Producto. La condición marcada es que el valor del campo Producto tiene que ser igual a “Naranja”, luego sólo obtendremos aquellos registros que cumplan dicha condición.

Podemos poner condiciones sobre varios campos. Por ejemplo, si queremos recuperar los proveedores que nos suministran Naranjas a un precio inferior a 2 euros, ejecutaríamos la siguiente sentencia:

SELECT NombreProveedor, Producto, Precio FROM ProductosEnProveedores

WHERE ((Producto=»Naranja») AND (Precio<2));

El resultado nos da 4 proveedores, hemos perdido uno, el que nos suministraba Naranjas a un precio mayor de 2 euros.

Utilizamos el conector lógico AND que obliga a que se cumplan ambas condiciones.

También podemos emplear el modificador BETWEEN para indicar que un valor tiene que estar entre dos limites. Imaginemos que queremos conocer que proveedores nos suministran Naranjas a un precio inferior a 2 euros pero superior a 1,5 euros, ya que por debajo de este último precio pensamos que las Naranjas que recibiríamos serían de muy mala calidad. Para obtener estos datos, modificamos la anterior consulta como se muestra a continuación:

SELECT NombreProveedor, Producto, Precio FROM ProductosEnProveedores

WHERE ((Producto=»Naranja») AND (Precio BETWEEN 1.5 AND 2));

Como he comentado antes, el operador lógico AND obliga a que ambas condiciones sean ciertas para que el total sea verdadero. Tenemos también el operador OR que arrojaría un valor verdadero para la expresión total, simplemente con que una de las dos condiciones fuera cierta. Estos operadores lógicos los encontramos en todos los lenguajes de programación, así que no me voy a extender con ellos, sencillamente pondré un ejemplo con OR.

Supongamos que queremos saber que proveedores nos suministran Naranjas o Manzanas. La consulta a ejecutar sería:

SELECT NombreProveedor, Producto, Precio FROM ProductosEnProveedores

WHERE ((Producto=»Naranja») OR (Producto=»Manzana»));

Paso 6: El modificador LIKE

También podemos buscar una cadena de texto en el valor de un campo, empleando el modificador like. Por ejemplo, si queremos recuperar los nombres de los proveedores que tengan la cadena de caracteres “ar” en su nombre, ejecutaríamos la sentencia:

SELECT NombreProveedor FROM Proveedores

WHERE (NombreProveedor Like «*» & «ar» & «*»);

Esta vez volvemos a la tabla Proveedores, y obtenemos dos resultados:

Arroces La Cigala

Azucarera Sevillana

Paso 7: Trabajando con varias tablas

Supongamos ahora que queremos saber los proveedores que nos suministran Naranjas, pero queremos también recuperar el contacto del proveedor y su número de teléfono, para poder llamarles directamente. En esta situación, tenemos que utilizar ambas tablas, la tabla Proveedores y la tabla ProductosEnProveedores, empleando la relación entre ambas tablas que establecíamos a través del campo NombreProveedor.

La sentencia para ejecutar la consulta mencionada sería:

SELECT Proveedores.NombreProveedor, Proveedores.ContactoProveedor, Proveedores.Telefono, ProductosEnProveedores.Producto, ProductosEnProveedores.Precio

FROM Proveedores INNER JOIN ProductosEnProveedores ON Proveedores.NombreProveedor = ProductosEnProveedores.NombreProveedor

WHERE (((ProductosEnProveedores.Producto)=»Naranja»));

En este caso, tras la cláusula SELECT, escribimos todos los campos que vamos a mostrar pero hay que indicar también la tabla en la que se encuentran. Esto es necesario porque podemos tener campos con el mismo nombre en distintas tablas, como nos ocurre en este caso con el campo NombreProveedor, el que empleamos para crear la relación entre las dos tablas.

Si eliminamos la cláusula WHERE, tendríamos todos los registros completos, lo que teníamos en el fichero proveedores antes de migrar nuestros datos a una BBDD relacional.

SELECT Proveedores.NombreProveedor, Proveedores.ContactoProveedor, Proveedores.Telefono, ProductosEnProveedores.Producto, ProductosEnProveedores.Precio

FROM Proveedores INNER JOIN ProductosEnProveedores ON Proveedores.NombreProveedor = ProductosEnProveedores.NombreProveedor

En la cláusula FROM establecemos la relación entre ambas tablas usando el operador INNER JOIN, es decir, incluimos las filas donde los campos combinados de ambas tablas sean iguales. Con lo que si tenemos algún registro de proveedor que no nos suministra ningún producto, no saldrá en la foto.

Probemos esto último. Añadimos el siguiente proveedor a la tabla Proveedores:

NombreProveedor = Remolacha de Atapuerca

NombreContacto = Primitivo Dalmao

Telefono = 654196745

Si ejecutamos la consulta de antes, obtenemos el mismo resultado, ya que Remolacha de Atapuerca no tiene ningún registro en la tabla ProductosEnProveedores.

Sin embargo, si cambiamos el operador INNER por LEFT, estaremos incluyendo todos los registros de la tabla de la izquierda (Proveedores) y sólo aquellos de la tabla de la derecha (ProductosEnProveedor) donde los campos combinados sean iguales. Ejecutamos la siguiente sentencia SQL:

SELECT Proveedores.NombreProveedor, Proveedores.ContactoProveedor, Proveedores.Telefono, ProductosEnProveedores.Producto, ProductosEnProveedores.Precio

FROM Proveedores LEFT JOIN ProductosEnProveedores ON Proveedores.NombreProveedor = ProductosEnProveedores.NombreProveedor

Y en resultado podemos observar que nos aparece el proveedor Remolacha de Atapuerca aunque no tiene ningún producto asociado, ese campo y el de precio aparecen vacios.

NOTA:

Este post es parte de la colección “Arquitectura de Datos” que reproduce los apuntes de la clase que imparto sobre el tema en ESIC. Puedes ver el índice de esta colección aquí.