Supongamos que adicionamos al modelo con el que hemos trabajado, la posibilidad de almacenar varios teléfonos asociados a un mismo cliente, indicando además que tipo de teléfono es (fax, trabajo, móvil, casa), y detalles sobre días de la semana y horas en que se aconseja llamar a ese teléfono.
Luego nos solicitan obtener los datos de los 3 clientes que más han aportado a la compañía en el año 2012 conjuntamente con el valor total del importe, mostrando además todos sus teléfonos con las características adicionales.
Muestro a continuación las mejoras al modelo que hemos estado utilizando, donde se incluyen dos nuevas tablas, una donde se especifican los tipos de teléfonos y otra donde se almacenarán propiamente los teléfonos asociados a cada cliente. Pierde sentido mantener el campo telefono de la tabla clientes.
Evidentemente para dar solución a este problema no podemos limitar la consulta a solo 3 registros, pues no obtendríamos el resultado correcto, ya que un cliente puede tener más de un teléfono.
Obtengamos primeramente los 3 clientes solicitados (problema similar abordado en otro post), y luego veamos cómo obtener sus teléfonos en la misma consulta. Está claro que para la presentación de esta información, sea cual sea la plataforma o aplicación se necesita luego de un procesamiento previo, muchas veces incluidas implícitamente en los motores de plantillas de reportes, o de generación de páginas web dinámicas, a partir de un agrupamiento del conjunto de datos.
En postgres esta sería una solución a esa primera consulta:
SELECT c.id_cliente, c.nombre, c.direccion, c.ciudad, SUM(a.precio_unitario*a.cantidad) AS importe_total FROM clientes c INNER JOIN ordenes o ON (c.id_cliente=o.cliente) INNER JOIN articulos a ON (a.orden=o.id_orden) WHERE EXTRACT(YEAR FROM o.fecha) = 2012 GROUP BY c.id_cliente, c.nombre, c.direccion, c.ciudad ORDER BY importe_total DESC LIMIT 3
Si utilizáramos un enlace de la tabla clientes con la tabla telefonos_clientes para obtener los teléfonos, no tendríamos forma de conocer a cuántos registros debemos limitar el resultado, por lo que una posible solución es utilizar la consulta anterior como subconsulta a la que haremos un enlace con la tabla telefonos_clientes para obtener todos los telefonos de los clientes obtenidos en la subconsulta.
SELECT c.id_cliente, c.nombre, c.direccion, c.ciudad, c.importe_total, t.numero as telefono, tt.nombre as tipo_telefono, t.detalles FROM ( SELECT c.id_cliente, c.nombre, c.direccion, c.ciudad, SUM(a.precio_unitario*a.cantidad) AS importe_total FROM clientes c INNER JOIN ordenes o ON (c.id_cliente=o.cliente) INNER JOIN articulos a ON (a.orden=o.id_orden) WHERE EXTRACT(YEAR FROM o.fecha) = 2012 GROUP BY c.id_cliente, c.nombre, c.direccion, c.ciudad ORDER BY importe_total DESC LIMIT 3 ) c LEFT JOIN telefonos_clientes t ON (c.id_cliente=t.cliente) LEFT JOIN tipos_telefonos tt ON (t.tipo=tt.id_tipo) ORDER BY c.importe_total DESC
Note que el enlace con telefonos_clientes se hace utilizando un LEFT JOIN, pues puede suceder que algunos clientes no tengan teléfonos asociados. Note además que para garantizar que el resultado final nos muestre los clientes ordenados por importe de mayor a menor, es obligatorio volver a ordenar por ese valor en la consulta exterior.
Esto es todo por ahora, en la próxima entrada estaremos hablando sobre cómo definir y obtener un índice de popularidad basado en resultados históricos.