domingo, 30 de agosto de 2015

FULL OUTER JOIN y un ejemplo de la vida real


FULL OUTER JOIN es una instrucción usada para consultar dos tablas en las cuales se desea mostrar todos los registros coincidentes en ellas y los registros no coincidentes en las mismas. Bajo condiciones normales de diseño esto no debería ocurrir, sin embargo, hace muchos años me tocó migrar un sistema realizado en tablas Clarion TopSpeed en el cual las reglas de integridad la manejaban las aplicaciones.

Había una regla de negocio muy particular que indicaba que toda factura debía llevar un número de cliente pero que cuando se desconocieran los datos del cliente, el número del cliente (en la factura) debía ser cero. Por otro lado, el cliente cero en la base de datos no existía por lo que al migrar los datos a un esquema de base de datos relacional las reglas de integridad no lo permitían.

Utilizaremos esta situación para ilustrar el uso del FULL OUTER JOIN. En este caso se requiere:

  • Mostrar los clientes con los datos de sus facturas.
  • Mostrar los clientes sin facturas con los datos de las facturas en NULL.
  • Mostrar los clientes inexistentes con sus datos en NULL (el cliente cero, en este caso) con los datos de las facturas generadas.

Usando el esquema de nuestras publicaciones anteriores, la consulta quedaría así:

SELECT * FROM 
CLIENTE AS C FULL OUTER JOIN FACTURA AS F 
ON C.ID_CLIENTE = F.ID_CLIENTE;

A esta consulta se le puede agregar una cláusula WHERE para ejecutar condiciones de búsqueda. Recordemos que el gestor de base de datos ejecutará primero las cláusulas OUTER y finalmente las cláusulas WHERE.

sábado, 29 de agosto de 2015

LEFT OUTER JOIN y RIGHT OUTER JOIN

En nuestra publicación anterior hablamos sobre el OUTER JOIN, indicamos que académicamente éstos eran conocidos como “reuniones” y que entre las distintas reuniones que podían realizarse estaban las “reuniones por la izquierda” y las “reuniones por la derecha”.

Recordemos que un OUTER JOIN es una consulta que se realiza entre dos tablas cuando se requiere que aparezcan todos los registros de una de ellas sin importar que en la otra existan registros relacionados. Si la tabla que contiene todos los registros está a la “izquierda” de la cláusula JOIN, debe utilizarse un “LEFT OUTER JOIN” y si esta tabla está a la “derecha” de la cláusula JOIN, debe utilizarse un “RIGHT OUTER JOIN”.

En la publicación anterior se usó como ejemplo una consulta que mostraba la información de los clientes y sus facturas: si el cliente no tenía facturas, la información de éstas vendría con valores NULL. Esto se escribió de la siguiente manera:

SELECT * FROM 
CLIENTE AS C LEFT OUTER JOIN FACTURA AS F 
ON C.ID_CLIENTE = F.ID_CLIENTE;

En este caso, se utilizó un LEFT OUTER JOIN ya que la tabla con todos los registros (Clientes) está a la izquierda de la instrucción LEFT OUTER JOIN. Si la tabla de clientes hubiera estado a la derecha del JOIN, esta consulta hubiera traído resultados idénticos:

SELECT * FROM 
FACTURA AS F RIGHT OUTER JOIN CLIENTE AS C
ON F.ID_CLIENTE = C.ID_CLIENTE;

Las reuniones por la izquierda y la derecha son conceptos antagónicos pero al ser implementadas racionalmente se obtienen resultados idénticos.

jueves, 27 de agosto de 2015

OUTER JOINS ¿Qué son?


Cuando creamos una base de datos, estos últimos se distribuyen entre varias tablas. Esto ocurre ya que nuestro diseño se deriva del modelo relacional de datos, el cual considera a la base de datos como un conjunto de relaciones, las cuales en nuestro gestor se implantan como tablas vinculadas a otras por medio de claves foráneas.

Sin pérdida de generalidad, propondremos como ejemplo una base de datos con dos tablas: Cliente que posee los atributos código del cliente y nombre y Factura que posee como atributos el número de la factura, su fecha de creación y el código del cliente al que pertenece. Los campos señalados en cursivas son las claves primarias de cada tabla.

Escribiendo cada tabla en forma de relaciones, éstas quedan de la siguiente manera:

cliente (id_cliente,nombre)
factura(id_factura, fecha, id_cliente)

Suponiendo que queremos  realizar una consulta que nos permita mostrar los clientes con las facturas que han generado, esto nos coloca en una situación de realizar una vinculación o reunión natural (NATURAL JOIN) entre la tabla de clientes y la tabla de facturas. Esto lo podemos resolver de la siguiente manera:

SELECT * FROM CLIENTE AS C, FACTURA AS F 
WHERE C.ID_CLIENTE = F.ID_CLIENTE;

Esto solamente nos mostrará los datos de los clientes sí y sólo sí estos clientes tienen al menos una factura.

Supongamos que ahora queremos mejorar la consulta para que traiga los clientes de nombre Lugo sin importar que los clientes tengan o no facturas. Al modificar la consulta anterior ésta quedaría de la siguiente manera:

SELECT * 
FROM CLIENTE AS C, FACTURA AS F 
WHERE C.ID_CLIENTE = F.ID_CLIENTE AND NOMBRE='Lugo';

Esta consulta no traerá el resultado esperado ya que sólo traerá a los clientes cuyo nombre es Lugo pero con la condición adicional de que haya generado al menos una factura. Observe que el nuevo enunciado indica que debe mostrarse a las personas de nombre Lugo sin importar que tenga o no facturas.

Necesitamos hacer una consulta por medio de la cual el gestor de base de datos haga el siguiente trabajo:


  1. Cruzar todos los datos de la tabla de clientes con la de factura.
  2. Todos los registros coincidentes de la tabla de clientes y facturas traerlos con sus datos completos tanto de clientes como de factura.
  3. Si existen clientes que no tengan facturas, traer los datos de cliente como están y los de factura en NULL. (Ya que justamente, estos clientes no tienen datos de facturas)
  4. Una vez unidos los registros de los pasos 3 y 4, filtrar los de nombre Lugo.


Para realizar esto, ejecutaremos la siguiente consulta:

SELECT * FROM 
CLIENTE AS C LEFT OUTER JOIN FACTURA AS F 
ON C.ID_CLIENTE = F.ID_CLIENTE 
WHERE NOMBRE='Lugo';

Esta consulta hará exactamente lo que hemos descrito en los pasos 1, 2, 3 y 4.

Académicamente, los OUTER JOIN se conocen también como “reuniones”. Existen “reuniones por la izquierda” (LEFT OUTER JOIN) en la cual se combinan los valores de la tabla de la izquierda con los de la derecha (como en este ejemplo) y “reuniones por la derecha” donde se combinan los valores de la tabla de la derecha con los de la izquierda.

Finalizaremos diciendo que un OUTER JOIN es un enlace entre dos tablas en el cual se requiere ver todas las filas de una de ellas sin importar que existan correspondencias en los registros de la otra tabla.

miércoles, 26 de agosto de 2015

Las estadísticas y el optimizador de consultas

Una de las características más comunes e importantes de los gestores de bases de datos es el optimizador de consultas. Éste utiliza diversos cálculos y estadísticas almacenadas dentro del catálogo de la base de datos para utilizarlos cuando se ejecuta una instrucción de SQL.

El optimizador de consultas determina por medio de estas estadísticas cuál es la acción que debe tomarse para asegurar que la consulta se ejecute de manera eficiente. Entre las variables que los optimizadores toman en cuenta para determinar manera de ejecución están la distribución y frecuencia de los datos (normalmente conocida como histogramas), páginas utilizadas por los datos, distribución y cardinalidad de los índices.

Todas estas variables conjuntamente con la cantidad de memoria disponible así como la disponibilidad del procesador juegan un papel crucial al ejecutar una consulta ya que basado en todas estas condiciones el optimizador tomará el camino más adecuado para acceder a los datos almacenados.

En SQL Server es posible consultar el catálogo de base datos para saber si las estadísticas están habilitadas con el siguiente comando:

USE MASTER;

SELECT NAME , IS_AUTO_CREATE_STATS_ON FROM SYS.DATABASES;

En condiciones normales, la variable IS_AUTO_CREATE_STATS_ON debe valer 1 para indicar que estas estadísticas están habilitadas.

En caso de no estar habilitadas las estadísticas para una base de datos, puede usarse el siguiente comando:

ALTER DATABASE [NOMBRE_DE_LA_BD] SET AUTO_UPDATE_STATISTICS OFF/ON;

Lo que desactivará o activará las estadísticas que usará el optimizador.

Debe tener permisos de administrador en la base de datos para poder ejecutar estos comandos.