Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Como realizar consulta SQL para validar si un numero no forma parte de un rango (https://www.clubdelphi.com/foros/showthread.php?t=90163)

darkamerico 19-04-2016 18:59:41

Como realizar consulta SQL para validar si un numero no forma parte de un rango
 
Saludos amigos, estoy implementando un sistema de Horarios para mi Facultad, ya casi esta todo hecho; estoy usando el componente TPlanner de TMS Component Pack para XE10, el detalle de los horarios los tengo en una tabla llamada horario_detalle la cual tiene la siguiente estructura:



Algunos datos de la tabla mencionada:



El problema con todo sistema horarios es evitar que se asignen cursos que se crucen con otros previamente asignados y ese es el tema aqui, les explico:



Lo que necesito es mejorar la consulta sql que estoy usando para validar los casos de cruce:

Código SQL [-]
SELECT
horario_detalle.id_horariodet,
horario_detalle.posIniGrid,
horario_detalle.posFinGrid
FROM
horario_detalle
INNER JOIN curso ON horario_detalle.idcurso_fk = curso.id_curso
WHERE
horario_detalle.idsemestre_fk = :IDSemestre AND
horario_detalle.idcurr_fk = :IDCurr AND
horario_detalle.idfacultad_fk = :IDFacultad AND
horario_detalle.iddptoacad_fk = :IDDpto AND
horario_detalle.iddia = :IDDia AND
horario_detalle.posIniGrid BETWEEN :PosIni AND :PosFin AND
curso.ciclo = :Ciclo


Muchas Gracias por su atencion

elrayo76 19-04-2016 21:32:13

Te paso parte del wehere que usaba yo en su momento para validar algo similar a lo tuyo. Yo lo hacia por fechas pero se puede itilizar con cualquier tipo de datos numéricos.

Código SQL [-]
     AND (   (    inCampoDesde <= CampoDesde                 
                  AND inCampoHasta >= CampoDesde
                )

             OR (    inCampoDesde >= CampoDesde
                 AND inCampoHasta <= CampoHasta
                )

             OR (    inCampoDesde <= CampoHasta
                 AND inCampoHasta >= CampoHasta
                )

             OR (    inCampoDesde <= CampoDesde
                 AND inCampoHasta >= CampoHasta
                )

Todo lo que comienza con 'in' lo debes reemplazar por lo que se ingresa desde tu aplicación. El resto son los campos de tu tabla.

Analiza lo que te paso y cualquier duda consultas.

Saludos,
El Rayo

PD: Si luego ven los administradores que esto le puede servir a muchos mas, lo pueden pasar como truco.

elrayo76 19-04-2016 21:37:09

Olvide comentar que lo que puse en el mensaje anterior va a reemplazar al BETWEEN, ya que este no valida si solo se superpone una parte del rango, luego lo demas puede quedar como esta. Además yo esto lo usaba en consultas de Oracle.

Saludos,
El Rayo

darkamerico 19-04-2016 22:14:15

Gracias amigo
 
Un caluroso saludo Rayo, mira puse en ejecución el código que me diste y sintácticamente funciona:

Código SQL [-]
SELECT
horario_detalle.id_horariodet,
horario_detalle.posIniGrid,
horario_detalle.posFinGrid
FROM
horario_detalle
INNER JOIN curso ON horario_detalle.idcurso_fk = curso.id_curso
WHERE
horario_detalle.idsemestre_fk = 1 AND
horario_detalle.idcurr_fk = 1 AND
horario_detalle.idfacultad_fk = 1 AND
horario_detalle.iddptoacad_fk = 1 AND
horario_detalle.iddia = 1 AND
((horario_detalle.posIniGrid>=0 AND horario_detalle.posFinGrid<=2)
  OR 
 (horario_detalle.posIniGrid>=0 AND horario_detalle.posFinGrid<=2)) AND
curso.ciclo = 10

Aquí asumo que un horario nuevo se quiere instalar el iddia=1 (Martes) entre las horas 0 (7:00am) a 2 (9:00am) cuando Ya existe un horario asignado a esa hora, y si, efectivamente arroja el id_horariodet correspondiente al horario asignado, pero que pasa si alguien quiere instalar un horario en iddia=1 entre las horas 1 (8:00am) y 3 (10:00am) donde existe cruce igualmente?


Saludos y Gracias

mamcx 19-04-2016 22:45:28

Curiosamente un motor sql deberia hacer esto super simple (ya que esto es manejo basico de relaciones), pero desafortunadamente todo depende de las abilidades programaticas de cada motor.

Esta es la forma basica (ej en python):

Código PHP:

>>> range(1,10)
>>> 
range(8,20)
>>> 
xs set(x)
>>> 
xs.intersection(y)
set([89]) 

El problema es como generar la lista de fechas en memoria, y eso depende de tu motor. La idea es hacer algo como:

Código SQL [-]
SELECT Fecha FROM FuncionGeneradora(Inicio, Fin)
-- 1 registro por cada hora entre inicio y fin

Y de ahi usas sql estandar para la interseccion

elrayo76 19-04-2016 23:19:59

Amigo darkamerico, te comento lo que hace lo que puse en el SQL.

1) Mira que no se crucen los datos estando los valores ingresados fuera de los rangos existentes o sean iguales a los límites.
2) Mira que no se crucen los datos estando los valores ingresados dentro del rango existente.
3) Mira que el rango tenga el desde dentro del rango existente pero el hasta puede estar dentro o fuera
4) Lo mismo que el anterior pero alrevez, el desde puede estar fuera pero el hasta dentro.

Pongo ejemplo con tu caso

Inicio = 2 / Fin = 4

Ingresan:

Inicio = 1 / Fin = 5 --> Primera validacion de mi SQL

Inicio = 2 / Fin = 5 --> Segunda validacion de mi SQL

Inicio = 2 / Fin = 4 --> Tercera validacion de mi SQL

Inicio = 1 / Fin = 4 --> Cuarta Validacion de mi SQL

Con este ejemplo creo que te debería quedar mas claro porque todas esas validaciones. Creeme que fue analizado mucho de hacerlo asi por tema de performance y no hay otra forma de hacerlo.


mamcx, como haces en tu código para validar si solo el inicio esta dentro del rango y el fin esta fuera o viceversa?. Por lo que entendi no lo puede hacer, dime si me equivoco.

Saludos,
El Rayo

mamcx 20-04-2016 00:06:59

Lo que digo es que si se el motor que usa puede generar fechas en memoria puede usar sql estandar para hacer el chequeo. Osea, es armar una tabla en memoria con registros como:

Cita:

12-01-01 1pm
12-01-01 2pm
12-01-01 3pm

darkamerico 20-04-2016 00:11:58

Una observacion final
 
La consulta implementada quedó como sigue:

Código SQL [-]
SELECT
horario_detalle.id_horariodet,
horario_detalle.posIniGrid,
horario_detalle.posFinGrid
FROM
horario_detalle
INNER JOIN curso ON horario_detalle.idcurso_fk = curso.id_curso
WHERE
horario_detalle.idsemestre_fk = :IDSemestre AND
horario_detalle.idcurr_fk = :IDCurr AND
horario_detalle.idfacultad_fk = :IDFacultad AND
horario_detalle.iddptoacad_fk = :IDDpto AND
horario_detalle.iddia = :IDDia AND
((:PosIni <= horario_detalle.posIniGrid AND :PosFin >= horario_detalle.posFinGrid)
  OR 
 (:PosIni >= horario_detalle.posIniGrid AND :PosFin <= horario_detalle.posFinGrid)
  OR
 (:PosIni <= horario_detalle.posFinGrid AND :PosFin >= horario_detalle.posFinGrid)
  OR 
 (:PosIni <= horario_detalle.posIniGrid AND :PosFin >= horario_detalle.posFinGrid)) AND
curso.ciclo = :Ciclo

Solo una observacion final: Si Existe un horario de hora=0 (7:00am) a hora=2 (9:00am) y quiero asignar un horario nuevo de 9:00am a 11:00am no me permite.

Un abrazo

elrayo76 20-04-2016 02:40:29

Porque no te deja asignar el horario que quieres?. No se que es lo que te está devolviendo la consulta completa que pusiste.

Igualmente fijate que te equivocaste en un dato de la consulta. Te pongo tal cual como debes copiarla y pegarla.

Código SQL [-]
((:PosIni <= horario_detalle.posIniGrid AND :PosFin >= horario_detalle.posIniGrid)
  OR 
 (:PosIni >= horario_detalle.posIniGrid AND :PosFin <= horario_detalle.posFinGrid)
  OR
 (:PosIni <= horario_detalle.posFinGrid AND :PosFin >= horario_detalle.posFinGrid)
  OR 
 (:PosIni <= horario_detalle.posIniGrid AND :PosFin >= horario_detalle.posFinGrid))

Saludos,
El Rayo

darkamerico 20-04-2016 14:29:04

Omg!
 
Grande Rayo, la cosa funcionó!!!!

elrayo76 20-04-2016 14:48:32

Fue un gusto haberte ayudado, ya que a mi me han ayudado muchas veces.

Saludos,
El Rayo


La franja horaria es GMT +2. Ahora son las 16:46:44.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi