sábado, 23 de agosto de 2008

Choques de horarios en SQL Server

El problema era el siguiente: para el desarrollo de un sistema que controla los horarios de clases, los posibles choques de horarios y aulas que pueden existir entre diferentes actividades, es decir, saber cuando se programe el calendario de una actividad no choque con otra actividad ya que esta otra pueda estar usando el mismo aula, a la misma hora en el mismo dia.

Por ejemplo, si ingreso al sistema una actividad "A" que son los lunes, miercoles y viernes de 4pm a6pm del 1 de agosto al 15 de agosto utilizando el aula ABC, al momento que se intente de ingregar una actividad "B" que sean los martes, miercoles y sabados, de 5pm a 7pm utilizando el aula ABC del 10 al 20 de agosto no me permita hacerlo, ya que para la actividad "A" los miercoles cochan una hora en especial (coinciden de 5pm a 6pm) y comparten comparten 5 dias en comun (del 10 al 15 de agosto) y dentro de esos 5 dias hay un miercoles de por medio.

En pocas palabras la sentencia SQL deseada debe tomar encuenta todas estas variables: aula, dia, horas, fechas de duracion de los cursos y determinar si todas estas variables coinciden en algun momento por mas pequeña que sea la coincidencia (el choque).

Googleando un poco no encontre nada, absolutamente nada que me diera una idea, asi que me puse mano a la obra y aqui esta un store procedure que logra esto. El secreto esta en determinar dichos choques al momento de que definimos cada uno de los bloque de dias-horas por separados.

Yo poseo una tabla por cada elemento: Aulas, dias, actividad (descripciones de las diferentes actividades), actividad-calendario-encabezado (donde asigno la actividad y la fecha de duracion) y actividad-calendario-detalle (donde asigno los dias, el aula y las horas a cada renglon)

La horas debe ser en formato militar, es decir 12, 13, 14, etc., en vez de usar 12pm, 1pm, 2pm. De esta forma podemos crear el campo de hora como tipo numeric(4,3) para lograr nuestros objetivos.

CREATE PROCEDURE [dbo].[sp_horario_aula_choque]
@dia tinyint,
@aula int,
@ini numeric(4,2),
@fin numeric(4,2),
@fini datetime,
@ffin datetime

AS
BEGIN

SET NOCOUNT ON;

select * from dbo.vw_horario_aula_choque where aula_id = @aula and dia_id = @dia and
((@ini >= det_hini and @ini <> det_hini and @fin <>
(@ini <= det_hini and @fin >= det_hfin)) and
((@fini >= enc_fhinicio
and @fini <= enc_fhfinal) or (@ffin > enc_fhinicio and @ffin <= enc_fhfinal)
or (@fini <= enc_fhinicio and @ffin >= enc_fhfinal))
END

vw_horario_aula_choque es una vista que contiene la relacion de todas las tablas ya mencionadas.

Si el store procedure devuelve algun resultado existe un choque y este sera lo que nos presentara el SP.