2011-03-16 24 views
5

Estoy tratando de verificar agregue la siguiente restricción pero Oracle devuelve el error que se muestra a continuación.Usar fecha en una restricción de verificación, Oracle

ALTER TABLE Table1 
ADD (CONSTRAINT GT_Table1_CloseDate 
CHECK (CloseDate > SYSDATE), 
CONSTRAINT LT_Table1_CloseDate 
CHECK (CloseDate <= SYSDATE + 365)), 
CONSTRAINT GT_Table1_StartDate 
CHECK (StartDate > (CloseDate + (SYSDATE + 730)))); 

error:

Error report: 
SQL Error: ORA-02436: date or system variable wrongly specified in CHECK constraint 
02436. 00000 - "date or system variable wrongly specified in CHECK constraint" 
*Cause: An attempt was made to use a date constant or system variable, 
      such as USER, in a check constraint that was not completely 
      specified in a CREATE TABLE or ALTER TABLE statement. For 
      example, a date was specified without the century. 
*Action: Completely specify the date constant or system variable. 
      Setting the event 10149 allows constraints like "a1 > '10-MAY-96'", 
      which a bug permitted to be created before version 8. 

Respuesta

11

Una restricción de comprobación, por desgracia, no se puede hacer referencia a una función como SYSDATE. Lo que se necesita para crear un disparador que comprueba estos valores cuando se produce LMD, es decir

CREATE OR REPLACE TRIGGER trg_check_dates 
    BEFORE INSERT OR UPDATE ON table1 
    FOR EACH ROW 
BEGIN 
    IF(:new.CloseDate <= SYSDATE) 
    THEN 
    RAISE_APPLICATION_ERROR(-20001, 
      'Invalid CloseDate: CloseDate must be greater than the current date - value = ' || 
      to_char(:new.CloseDate, 'YYYY-MM-DD HH24:MI:SS')); 
    END IF; 
    IF(:new.CloseDate > add_months(SYSDATE,12)) 
    THEN 
    RAISE_APPLICATION_ERROR(-20002, 
     'Invalid CloseDate: CloseDate must be within the next year - value = ' || 
     to_char(:new.CloseDate, 'YYYY-MM-DD HH24:MI:SS')); 
    END IF; 
    IF(:new.StartDate <= add_months(:new.CloseDate,24)) 
    THEN 
    RAISE_APPLICATION_ERROR(-20002, 
      'Invalid StartDate: StartDate must be within 24 months of the CloseDate - StartDate = ' || 
      to_char(:new.StartDate, 'YYYY-MM-DD HH24:MI:SS') || 
      ' CloseDate = ' || to_char(:new.CloseDate , 'YYYY-MM-DD HH24:MI:SS')); 
    END IF; 
END; 
+1

Tenga en cuenta que para el segundo "restricción" LT_Table1_CloseDate, se puede utilizar una restricción de comprobación en 11g usando columnas virtuales (http://rwijk.blogspot.com/2007/12/check- constraints-with-sysdate.html) –

4

Todos y cada vez que el registro se actualiza SYSDATE tendrá un valor diferente. Por lo tanto, la restricción se validará de manera diferente cada vez. Oracle no permite sysdate en una restricción por ese motivo.

Puede resolver su problema con un desencadenador que comprueba si CloseDate realmente ha cambiado y genera una excepción cuando el nuevo valor no está dentro del rango.

Y: ¿Qué es (StartDate > (CloseDate + (SYSDATE + 730))))? No puedes agregar fechas.

Y: StartDate debe ser después deCloseDate? ¿No es extraño?

11

No puede usar SYSDATE en la restricción de verificación. Según la documentación

Conditions of check constraints cannot contain the following constructs:

  • Subqueries and scalar subquery expressions
  • Calls to the functions that are not deterministic (CURRENT_DATE,
    CURRENT_TIMESTAMP, DBTIMEZONE,
    LOCALTIMESTAMP, SESSIONTIMEZONE,
    SYSDATE, SYSTIMESTAMP, UID, USER, and USERENV)
  • Calls to user-defined functions
  • Dereferencing of REF columns (for example, using the DEREF function)
  • Nested table columns or attributes
  • The pseudocolumns CURRVAL, NEXTVAL, LEVEL, or ROWNUM
  • Date constants that are not fully specified

Para 10g Release 2 (10,2), ver constraint, y para 11g Release 2 (11,2) ver constraint.

Recuerde que una restricción de integridad es una declaración acerca de los datos de la tabla que es siempre true.

De todos modos: no sé exactamente lo que está tratando de lograr pero creo que puede usar activadores para este propósito.

3

Escriba sysdate en una columna y utilícelo para validación. Esta columna podría ser su columna de auditoría (Por ejemplo: fecha de creación)

CREATE TABLE "AB_EMPLOYEE22" 
(
    "NAME"  VARCHAR2 (20 BYTE), 
    "AGE"  NUMBER, 
    "SALARY" NUMBER, 
    "DOB"  DATE, 
    "DOJ"  DATE DEFAULT SYSDATE 
); 

Table Created  

ALTER TABLE "AB_EMPLOYEE22" ADD CONSTRAINT 
AGE_CHECK CHECK((ROUND((DOJ-DOB)/365)) = AGE) ENABLE; 

Table Altered 
0

Todo esto es posible cuando se hace un poco de trucos como esto:

CREATE OR REPLACE FUNCTION SYSDATE_DETERMINISTIC RETURN DATE DETERMINISTIC IS 
BEGIN 
    RETURN SYSDATE; 
END SYSDATE_DETERMINISTIC; 
/

CREATE TABLE Table1 (
    s_date DATE, 
    C_DATE DATE GENERATED ALWAYS AS (SYSDATE_DETERMINISTIC()) 
); 

ALTER TABLE Table1 ADD CONSTRAINT s_check CHECK (s_date < C_DATE); 

Por supuesto, la función SYSDATE_DETERMINISTIC es no determinista, pero Oracle permite declarar esto de todos modos.

Quizás en versiones futuras Oracle se vuelva más inteligente y ya no permita tales trucos.

0

I don `t recomiendo cantar factores desencadenantes como la restricción y para elevar excepciones, su lugar se puede utilizar una columna para almacenar SYSDATE como fecha de registro (si ya lo tienes, entonces puede usarlo) y luego su limitación compara este columna en lugar de SYSDATE

ALTER TABLE Table1 
ADD (REGISTER_DATE DATE); 

CREATE OR REPLACE TRIGGER trg_check_dates 
    BEFORE INSERT OR UPDATE ON table1 
    FOR EACH ROW 
BEGIN 
    :new.REGISTER_DATE := SYSDATE; 
END; 

ALTER TABLE Table1 
ADD (CONSTRAINT GT_Table1_CloseDate 
CHECK (CloseDate > REGISTER_DATE), 
CONSTRAINT LT_Table1_CloseDate 
CHECK (CloseDate <= REGISTER_DATE + 365)), 
CONSTRAINT GT_Table1_StartDate 
CHECK (StartDate > (CloseDate + (REGISTER_DATE + 730)))); 
Cuestiones relacionadas