Consultas

Uso de más de una tabla

Para la resolución de la mayoría de requerimientos es necesario trabajar con información que se obtiene de relacionar varias tablas. La forma de especificar qué tablas vamos a consultar es construir una lista de nombres de tablas en la cláusula from.

Si seleccionamos la BD Ejemplo, podemos preguntar por el

Nombre de los profesores y la descripción de las asignaturas que imparten

¿Dónde está la información solicitada? Consultando el esquema de la base de datos Ejemplo:

  • nombre (del profesor) se encuentra en la tabla PROFESORES y
  • descripción (de la asignatura) en ASIGNATURAS.
PROFESORES ( 
dni : varchar(10), 
nombre : varchar(40), 
categoria : char(4), 
ingreso : date )
Clave primaria: dni
ASIGNATURAS ( 
codigo : char(5), 
descripcion : varchar(35), 
creditos : number(3,1), 
creditosp : number(3,1) )
Clave primaria: codigo
IMPARTE ( 
dni : varchar(10), 
asignatura : 
char(5) )
Clave primaria: (dni, asignatura)
Clave ajena: dni → PROFESORES
Clave ajena: asignatura → ASIGNATURAS

Si no lo pensamos mucho podríamos ejecutar la siguiente orden confiando en el todopoderoso SGBD:


select nombre, descripcion 
from asignaturas, profesores

Obviamente, el resultado anterior no se corresponde con la información solicitada, hemos hecho un producto cartesiano entre dos conjuntos, la combinación de todos los nombres de profesor con todas las descripciones de asignatura.

En este caso, la relación entre profesores y asignaturas se encuentra en imparte que tiene 2 claves ajenas, una está asociada a la clave primaria de profesor y la otra a la clave primaria de asignaturas. Pensemos en imparte como un "puente" que nos permite enlazar la información de la primera tabla con la segunda: de profesores pasamos a imparte mediante el dni, y de imparte a asignaturas mediante el código de la asignatura PROFESORES ← dni=dni → IMPARTE ← asignatura=codigo → ASIGNATURAS

Necesitamos, por tanto, incluir la tabla imparte en el from, y especificar en el where las condiciones para concatenar las tuplas deseadas.

Nombre de los profesores y descripción de las asignaturas que imparten

    • (lo que debemos mostar): select nombre, descripcion
    • (donde está la información necesaria): from asignaturas, profesores, imparte
    • (igualando claves ajenas y claves primarias): where imparte.dni = profesores.dni and asignatura = codigo

Para entender mejor cómo se obtienen los resultados de una consulta podemos pensar que el orden de ejecución es

  1. from asignaturas, profesores, imparte (producto cartesiano)
  2. where profesores.dni = imparte.dni and asignatura = codigo (selección)
  3. select nombre, descripcion (proyección)

1.

select * from asignaturas, profesores, imparte 

2.

select * from asignaturas, profesores, imparte 
where profesores.dni = imparte.dni and asignatura = codigo 

3.

select nombre, descripcion 
from asignaturas, profesores, imparte where profesores.dni=imparte.dni and asignatura=codigo

Resumiendo, podemos decir que

  1. from establece la fuente de datos,
  2. where la información objetivo en bruto, y
  3. select la extracción de la información deseada.

IMPORTANTE: Esto no es necesariamente real, una de las ventajas de utilizar un SGBD es que las consultas se procesan de manera eficiente y de forma totalmente transparente para el usuario. Es sólo una forma de comprender las acciones básicas que representa cada parámetro de la orden select.


Nombres cualificados de atributo

Un nombre cualificado de atributo es el que especifica el nombre de la tabla a la que pertenece la columna:

    • profesores.dni
    • asignaturas.descripción

Es obligatorio utilizar nombres cualificados de atributo si hay ambigüedad, si varias tablas de la select tienen columnas que se llaman igual:

    • profesores.dni
    • imparte.dni

En cualquier otro caso no es necesario.

DNI y nombre de los profesores que imparten alguna asignatura

select profesores.dni, nombre 
from profesores, imparte 
where profesores.dni = imparte.dni

Es una orden correcta, sin ambigüedades. Pero si modificamos y no cualificamos el dni de la proyección:

select dni, nombre
from profesores, imparte 
where profesores.dni = imparte.dni

Esto nos genera un error, la cualificación ha de hacerse en toda la orden debido a que SQL no sabe de qué tabla debe mostrar el dni.

Error at Command Line:3 Column:0
Error report:
SQL Error: Column 'dni' in field list is ambiguous

También es útil cuando, a partir de varias tablas, se quieren todas las columnas de una y sólo alguna de las otras

select profesores.*, descripcion
from profesores, asignaturas, imparte
where profesores.dni = imparte.dni
and codigo = asignatura 

Sinónimos temporales de tabla

select * from tabla alias

Una cadena de caracteres a continuación del nombre de la tabla en el from, es un alias temporal, un nombre sustitutivo. Es recomendable para simplificar la escritura de la orden select o para hacerla más legible.

Es obligatorio para un producto cartesiano de una tabla por si misma:

select p1.nombre, p2.nombre
from profesores p1, profesores p2
where p1.nombre <> p2.nombre 

Cuando se define el sinónimo en el from, sustituye totalmente al nombre de la tabla (no se permite utilizar los dos simultáneamente en el select o el where). Por otro lado, no es necesario definir sinónimos para todas las tablas del from.

DNI y nombre de los profesores que imparten alguna asignatura (utilizando sinónimos temporales de tabla)

select p.dni, nombre
from profesores p, imparte i
where p.dni = i.dni  

Rangos

Expresiones del tipo 10 <= x <= 100 se pueden construir utilizando el operador de construcción de rangos BETWEEN. La sintaxis de tal subexpresión de la cláusula where es la siguiente:

expresión [NOT] BETWEEN expresión AND expresión  

Créditos y descripción de las asignaturas cuyo número de créditos está entre 5 y 8.

select creditos, descripcion 
from asignaturas 
where creditos between 5 and 8  

Listas

Mediante el operador IN se puede buscar un determinado valor en una lista construida usando constantes.

expresión [NOT] IN (listaValores)

Descripción de las asignaturas FBD y DGBD.

select descripcion 
from asignaturas 
where codigo in ('FBD', 'DGBD')

Nombre de los profesores que no imparten HI, FBD o DGBD.

select nombre 
from profesores p, imparte i 
where p.dni = i.dni 
and asignatura not in ('HI', 'FBD', 'DGBD')

Fijémonos en que MANUEL PALOMAR, que no imparte ninguna de las asignaturas objeto de la búsqueda, tampoco aparece en la tabla resultado puesto que su dni no aparece en la tabla IMPARTE.

Subcadenas de caracteres

Podemos preguntar por subcadenas dentro de columnas de tipo carácter. Para ello utilizaremos los operadores LIKE (o MATCHES), que soportan la siguiente sintaxis:

expresión [NOT] LIKE 'cadena' 


La cadena de caracteres cadena admite los comodines % (tanto por ciento) y _ (subrayado):

  • % indica una cadena de caracteres de cualquier longitud (Ali% = Alicante, Aligerar, Ali, ...)
  • _ un carácter cualquiera (Ali_ = Alic, Alig, Ali, ...)

Profesores que atiendan al nombre de 'RAFA'.

select * from profesores where nombre like 'RAFA%' 

Código de las asignaturas de 'Bases de Datos'

select codigo from asignaturas where descripcion like '%BASES DE DATOS%' 

Código de las asignaturas, siendo tal código de 2 caracteres

select codigo from asignaturas where codigo like '__' 

Descripción de las asignaturas cuya última palabra contiene 'INFORMATIC' y un caracter adicional.

select descripcion from asignaturas where descripcion like '%INFORMATIC_'

Consultas anidadas

A veces, las condiciones de filtrado de tuplas o de cálculos de agregación son más complejas que la simple comparación con una constante o un valor almacenado en una tabla. Este dato intermedio, no un resultado final, ha de obtenerse mediante una consulta auxiliar, una subconsulta.

En la condición de filtrado de la orden select (en la cláusula where o en la having) también podemos:

  • comparar una expresión con el resultado de otra orden select
  • determinar si el valor de una expresión está incluido en los resultados de otra orden select
  • preguntar si una orden select ha obtenido alguna fila.

Descripción y créditos de las asignaturas con menos créditos.

select descripcion, creditos
from asignaturas
where creditos = ( select min(creditos) from asignaturas )

En primer lugar se calcula la select anidada (entre paréntesis) y se obtiene el valor mínimo para la columna créditos de la tabla asignaturas. Con ese valor se compara tupla a tupla y se obtiene la asignatura (o asignaturas) cuya cantidad de créditos es igual al mínimo.

Es importante darse cuenta de que la comparación creditos = ? espera un único valor, no un conjunto de filas. De ahí que debamos asegurarnos que el resultado de la consulta anidada contiene una fila y una columna. Aparte, el tipo de datos debe ser consistente.

De lista de valores: inclusión

expr [NOT] IN (orden select)


También podemos consultar la pertenencia de un valor a la lista de valores devuelta por la subconsulta.

Obtener todos los datos de los profesores que imparten alguna asignatura.

select * from profesores
where dni IN (select dni from imparte)

O dicho de otra manera: "datos de los profesores cuyo dni aparece en la tabla imparte".

En este caso daría lo mismo procesar la orden

select distinct p.* 
from profesores p, imparte i
where p.dni = i.dni 

NOTA: usar IN de esta manera no genera filas duplicadas, consigue el mismo resultado que el modificador distinct de la segunda consulta. Mientras que IN va recorriendo la tabla PROFESORES y preguntando uno a uno si se encuentra en la tabla IMPARTE o no, la segunda realiza el producto cartesiano y descarta las filas en las que no coinciden los valores de DNI. Eso genera filas duplicadas que se eliminan con distinct.

Se verá más clara la utilidad de este operador si preguntamos justo lo contrario.

Obtener todos los datos de los profesores que no imparten asignaturas.

select * from profesores
where dni NOT IN (select dni from imparte) 

Fechas y tiempos

La administración y manejo de valores temporales es la parte de los motores de base de datos menos estandarizada y con más diferencias entre uno y otro. Aparte, y junto con la codificación de caracteres y las características regionales (por ejemplo, formato de las fechas) el motor ofrecee un conjunto de parámetros globales del sistema que el administrador del mismo debe comprender y tener presente, dependiendo del contexto en el que se vayan a ver los resultados de una consulta. Si fuera a formar parte de un conjunto de páginas web dinámicas, no solo el servidor de base de datos debe estar correctamente configurado sino que debe tener en cuenta el servidor http, el del lenguaje huesped (php, por ejemplo) e incluso los clientes (navegadores, ordenadores, etc.).

Puestas así las cosas, aquí se va a tratar la superficie de todo lo que se puede hacer con fechas y tiempos, y siempre desde el punto de vista estrictamente de la consulta SQL.

MySQL ofrece varios tipos de datos relacionados con el tiempo:

  • DATETIME '0000-00-00 00:00:00'
  • DATE '0000-00-00'
  • TIMESTAMP 00000000000000
  • TIME '00:00:00'
  • YEAR 0000

Lo que se muestra en la lista anterior da una idea de qué datos maneja cada tipo. En realidad, lo anterior es la relación de "valores cero" que pueden almacenar y que tienen carácter de valor por defecto o valor de prueba. Dejando de lado el tipo TIMESTAMP que tiene unas propiedades y aplicaciones propias, todos los tipos están relacionados y difieren en cuanto a las limitaciones de almacenamiento y, más importante, de conversión automática de tipos.