Ir al contenido


Foto

Validación fecha Firebird


  • Por favor identifícate para responder
10 respuestas en este tema

#1 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 17 febrero 2009 - 06:59

Hola amigos del foro, tengo una tabla en una Db de Firebird 2.1 con  la siguiente estructura:

sql
  1. CREATE TABLE ASIGNACIONES (
  2.     ID_ASIGNACION  INTEGER NOT NULL,
  3.     ID_ASESOR      INTEGER NOT NULL,
  4.     FECHA_INICIO  DATE NOT NULL,
  5.     FECHA_FIN      DATE,
  6.  
  7.  
  8.     PRIMARY KEY (ID_ASIGNACION),
  9.     CONSTRAINT FK_ASIGN_ASESOR FOREIGN KEY (ID_ASESOR)
  10.       REFERENCES ASESORES (ID_ASESOR) ON UPDATE CASCADE,
  11.     CONSTRAINT CK_FECHA_ASIGNACION_INCORRECTA
  12.       CHECK (FECHA_FIN >= FECHA_INICIO)
  13. );



Como pueden ver a un asesor se le asigna una fecha de inicio y una fecha de finalización, mi pregunta es cómo podría validar a nivel de la DB para que al agregar un nuevo registro a un asesor dado, se asegure de que la nueva fecha de inicio sea mayor a la fecha de finalización del registro anterior del asesor dado? (Esto aplicaría para los assores que tuvieren mas de un registro).

Espero haberme explicado bien.

Gracias por su ayuda.
  • 0

#2 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 17 febrero 2009 - 07:20

Saludos.

Primeramente podrías crearte un indice descendente por el campo FECHA_FIN y luego hacer esta sentencia pondrías esto:



sql
  1. SELECT FIRST 1 FECHA_INICIO, FECHA_FIN
  2. FROM ASIGNACIONES
  3. WHERE FECHA_FIN = (SELECT MAX(FECHA_FIN) FROM ASIGNACIONES WHERE  ID_ASESOR = :PID_ASESOR)
  4. AND ID_ASESOR = :PID_ASESOR
  5. ORDER BY FECHA_FIN DESC



Lo hice sin probarlo pero la idea anda por ahí, ya almacenaras los datos en una variable y arrojaras una excepción.

Hasta luego.
  • 0

#3 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 17 febrero 2009 - 08:16

Gracias Rolphy por tu respuesta, ahora mi pregunta es si la solución que propones debo implementarla en un trigger (Before Insert)?

Gracias y disculpa mi ignorancia
  • 0

#4 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 17 febrero 2009 - 08:23

Compañeros quiero recoradar que mi inquietud es saber si es posible hacer esta implementación en la propia base de datos.

Gracias por su ayuda y su tiempo.
  • 0

#5 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 17 febrero 2009 - 08:28

Compañeros quiero recoradar que mi inquietud es saber si es posible hacer esta implementación en la propia base de datos.

Gracias por su ayuda y su tiempo.


Eso debes implementarlo en un Stored Procedure ;).

Saludos.
  • 0

#6 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 17 febrero 2009 - 08:38

Gracias Rolphy por tu respuesta, ahora mi pregunta es si la solución que propones debo implementarla en un trigger (Before Insert)?

Gracias y disculpa mi ignorancia


Bueno ahí viene el uso de la palabra mágica depende de tu necesidad.

Me refiero puede que hagas el INSERT vía un Stored Procedure, acá puedes modificar dicho Stored Procedure para que tenga la validación ahora bien si lo haces "plain" entonces lo más recomendable sería ponerlo en un Trigger (Before Insert).

Con la sentencia dada (claro con las pinceladas necesarias) en mi mensaje anterior y el uso de excepciones de la BD, puedes montar esta validación perfectamente dentro de la BD.

Ejemplo:


sql
  1. DECLARE VARIABLE VINICIO DATE;
  2. DECLARE VARIABLE VFIN DATE;
  3.  
  4. SELECT FIRST 1 FECHA_INICIO, FECHA_FIN
  5. FROM ASIGNACIONES
  6. WHERE FECHA_FIN = (SELECT MAX(FECHA_FIN) FROM ASIGNACIONES WHERE  ID_ASESOR = :PID_ASESOR)
  7. AND ID_ASESOR = :PID_ASESOR
  8. ORDER BY FECHA_FIN DESC
  9. INTO :VINICIO, :VFIN;
  10.  
  11. IF (VINICIO > VFIN) THEN
  12.   EXCEPTION EXCINICIOMAYORFINAL;
  13.   /*EXCINICIOMAYORFINAL es una excepción que creaste, en caso de no tener ninguna la sentencia quedaría así:
  14.  IF (VINICIO > VFIN) THEN
  15.   EXCEPTION EXCINICIOMAYORFINAL 'Fecha inicio mayor a la fecha final';
  16.  
  17.  */



Espero te sirva.
  • 0

#7 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 17 febrero 2009 - 09:04

Muchas gracias Rolphy y enecumene me quedó claro.

Saludos.

PD: Larga vida a este foro
  • 0

#8 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 19 febrero 2009 - 10:23

Finalmente y gracias a la enseñanza de Rolphy he  resuelto el problema para las inserciones de la siguientete manera:


sql
  1. CREATE  TRIGGER ASIGNACIONES_BI FOR ASIGNACIONES
  2. ACTIVE BEFORE INSERT POSITION 0
  3.  
  4. AS
  5. DECLARE VARIABLE VFIN DATE;
  6. DECLARE VARIABLE VMAX_ID INTEGER;
  7. BEGIN
  8.   SELECT MAX(ID_ASIGNACION)
  9.   FROM ASIGNACIONES
  10.   WHERE  ID_ASESOR = NEW.ID_ASESOR
  11.   INTO  :VMAX_ID;
  12.   IF (NOT VMAX_ID IS NULL) THEN /* Compruebo si dicho asesor tiene asignaciones,
  13.   puesto que si no las tiene no hay ninguna restricción */
  14.  
  15.   BEGIN
  16.     SELECT FECHA_FIN
  17.     FROM ASIGNACIONES
  18.     WHERE ID_ASIGNACION = :VMAX_ID
  19.     INTO :VFIN;
  20.     IF (VFIN IS NULL) THEN /* Compruebo que el registro anterior tenga fecha final*/
  21.   EXCEPTION FALTA_FECHA; /*Aviso que falta fecha en registro anterior*/
  22.   ELSE
  23.   IF (NEW.FECHA_INICIO <= VFIN) THEN /* Finalmente compruebo la fecha inicial del nuevo registro
  24.   contra la fecha final del registro anterior*/
  25.  
  26.   EXCEPTION FECHA_INCORRECTA;
  27.   END
  28. END



Ahora me falta resolver el Trigger (before update)para las actualizaciones, mi pregunta para los maestros del foro es si existe la posibilidad de recorrer una consulta en Firebird 2.1 y de que manera hacerlo, de ser posible con esa información podre implementar la validación para actualizaciones.

Muchas gracias por su tiempo y por su ayuda.

Saludos
  • 0

#9 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 19 febrero 2009 - 11:49

Saludos.

Me alegra que hayas podido resolver.  En cuanto al Trigger Before Update, no entiendo para que necesitas recorrer una consulta, si haces una actualización a la vez.

Debes de recordar que a partir de FB 1.5 tienes los Trigger Polivalentes, esto es que puedes indicar que un Trigger por ejemplo es tanto para Update como Insert al mismo tiempo.

Para recorrer una consulta te basta con esto:



sql
  1.   FOR SELECT CAMPO1, CAMPO2 FROM TABLA
  2.   INTO :VCAMPO1, VCAMPO2
  3.   DO
  4.   BEGIN
  5.     /*En esta parte haces lo que necesitas */
  6.     SUSPEND;
  7.   END;


  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 19 febrero 2009 - 12:33

A mi tampoco me queda claro para que correr una consulta...
Me gustaría saber a que está viniendo todo esto.
De todas formas, ya estás corriendo consultas en los triggers ;), la verdad es que no veo por que la duda...

Saludos,
  • 0

#11 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 19 febrero 2009 - 05:28

Gracias a Rolphy y Delphius por su interés.
La idea es que por cada asignación para determinado asesor, las fechas inicial y final sean consistentes, además de que las fechas de las asignaciones posteriores tambien sean mayores que las anteriores, inicio en la creación de la tabla con un Constraint que  revise que la fecha final sea mayor o igual que la inicial, con el trigger Before Insert me aseguro que al insertar un nuevo registro la fecha inicial de este sea mayor que la fecha final del registro anterior, hasta alli todo bien.

La idea de recorrer la consulta me surgía porqe tengo que  mostrar esta tabla como una tabla de detalles de la tabla de asesores, en donde había la posibilidad que el usuario final le diera por manipular asignaciones anteriores, por lo tanto era necesario comparar los cambios de fechas con las fechas de las asignaciones anteriores o posteriores para que los datos no perdieran consistencia; desistí de recorrer la consulta, a cambio hice un pequeño cambio en el diseño original de la tabla agregando un campo CONTADOR que se actualiza mediante los mismos triggers y con el cual (en caso de que cambien fechas) puedo facilmente comprobar la consistencia de los mismos.

La implementación final quedó como muestro a continuación y trabaja a la perfección, talvez haya muchas formas mas técnicas de lograr lo mismo pero hasta ahora me estoy familiarizando con Firebird. Si alguien tiene una idea mejor y dispone de tiempo y voluntad le ruego me lo haga saber para seguir aprendiendo.
Una vez mas muchas gracias por su ayuda e interés.

Saludos



sql
  1. CREATE EXCEPTION FALTA_FECHA
  2. 'Para poder ingresar una nueva asignación debe colocar una fecha final a la asignación anterior';
  3.  
  4. CREATE EXCEPTION FECHA_INCORRECTA
  5. 'La fecha que pretende utilizar ya se encuentra en otra asignación';
  6.  
  7. CREATE TABLE ASIGNACIONES (
  8.     ID_ASIGNACION  INTEGER NOT NULL,
  9.     ID_ASESOR      INTEGER NOT NULL,
  10.     FECHA_INICIO  DATE NOT NULL,
  11.     FECHA_FIN      DATE,
  12.     CONTADOR      INTEGER,
  13.  
  14.     PRIMARY KEY (ID_ASIGNACION),
  15.     CONSTRAINT FK_ASIGN_ASESOR FOREIGN KEY (ID_ASESOR)
  16.       REFERENCES ASESORES (ID_ASESOR) ON UPDATE CASCADE,
  17.     CONSTRAINT CK_FECHA_ASIGNACION_INCORRECTA
  18.       CHECK (FECHA_FIN >= FECHA_INICIO)
  19. );
  20.  
  21.  
  22. CREATE  TRIGGER ASIGNACIONES_BI0 FOR ASIGNACIONES
  23. ACTIVE BEFORE INSERT POSITION 0
  24. AS
  25. DECLARE VARIABLE VFIN DATE;
  26. DECLARE VARIABLE VMAX_ID INTEGER;
  27. DECLARE VARIABLE VMAX_CON INTEGER;
  28.  
  29. BEGIN
  30.   SELECT MAX(CONTADOR) /* Averiguo el número de la última asignación de un asesor*/
  31.   FROM ASIGNACIONES
  32.   WHERE  ID_ASESOR = NEW.ID_ASESOR
  33.   INTO  :VMAX_CON;
  34.  
  35.   SELECT MAX(ID_ASIGNACION)/* Consigo la clave principal para luego pasarla como parámetro*/
  36.   FROM ASIGNACIONES
  37.   WHERE  ID_ASESOR = NEW.ID_ASESOR
  38.   INTO  :VMAX_ID;
  39.  
  40.   IF (NOT VMAX_ID IS NULL) THEN /* Compruebo si dicho asesor tiene asignaciones,
  41.   puesto que si no las tiene no hay ninguna restricción */
  42.   BEGIN
  43.     NEW.CONTADOR = :VMAX_CON + 1; /*Incremento el valor del contador para el asesor en cuestión*/
  44.     SELECT FECHA_FIN
  45.     FROM ASIGNACIONES
  46.     WHERE ID_ASIGNACION = :VMAX_ID
  47.     INTO :VFIN;
  48.  
  49.     IF (VFIN IS NULL) THEN /* Compruebo que el registro anterior tenga fecha final*/
  50.     EXCEPTION FALTA_FECHA; /*Aviso que falta fecha en registro anterior*/
  51.     ELSE
  52.     IF (NEW.FECHA_INICIO <= VFIN) THEN /* Finalmente comparo la fecha inicial del nuevo registro
  53.     contra la fecha final del registro anterior*/
  54.     EXCEPTION FECHA_INCORRECTA;
  55.   END
  56. ELSE
  57.   NEW.CONTADOR = 1; /* Si dicho asesor no tiene asignaciones asignamos valor*/
  58. END
  59. ^
  60.  
  61.  
  62. CREATE  TRIGGER ASIGNACIONES_BU0 FOR ASIGNACIONES
  63. ACTIVE BEFORE UPDATE POSITION 0
  64. AS
  65. DECLARE VARIABLE VFIN DATE;
  66. DECLARE VARIABLE VINI DATE;
  67. DECLARE VARIABLE NUM INTEGER;
  68. BEGIN
  69.   SELECT MAX(CONTADOR) /*  Averiguo  la cantidad de asignaciones  de un asesor dado*/
  70.   FROM ASIGNACIONES
  71.   WHERE  ID_ASESOR = NEW.ID_ASESOR
  72.   INTO  :NUM;
  73.   IF (NUM <> 1) THEN /* Si solo tiene una asignación no tiene ninguna restricción */
  74. BEGIN
  75.   SELECT FECHA_FIN FROM asignaciones /*Averiguo la fecha final de la asignación anterior de ese asesor*/
  76.   WHERE (ID_ASESOR = NEW.id_asesor) AND (CONTADOR = OLD.CONTADOR - 1)
  77.   INTO VFIN;
  78.     IF (NOT VFIN IS NULL) THEN
  79.       IF (NEW.fecha_inicio <= VFIN) THEN/*La comparo con la fecha de inicio del registro actual*/
  80.       EXCEPTION fecha_incorrecta;
  81.   SELECT FECHA_INICIO FROM ASIGNACIONES  /*Averiguo la fecha inicial de la siguiente asignación de ese asesor*/
  82.     WHERE (ID_ASESOR = NEW.id_asesor) AND (CONTADOR =OLD.CONTADOR + 1)
  83.   INTO VINI;
  84.     IF (NOT VINI IS NULL) THEN
  85.       IF (NEW.fecha_FIN >= VINI) THEN/*La comparo con la fecha final del registro actual*/
  86.       EXCEPTION fecha_incorrecta;
  87. END
  88.  
  89. END
  90. ^
  91.  
  92. CREATE OR ALTER TRIGGER ASIGNACIONES_BD0 FOR ASIGNACIONES
  93. ACTIVE BEFORE DELETE POSITION 0
  94. AS
  95. BEGIN
  96.   UPDATE asignaciones SET contador = contador -1
  97.   WHERE ((contador >= OLD.contador) AND(ID_ASESOR = OLD.id_asesor));
  98.   /* Nos aseguramos que no queden huecos en el contador para quelos triggers */
  99.   /* BeforeInsert y BeforeUpdate funcionen correctamente*/
  100. END
  101. ^


  • 1




IP.Board spam blocked by CleanTalk.