在检查约束中使用日期,Oracle

在检查约束中使用日期,Oracle,oracle,date,constraints,Oracle,Date,Constraints,我试图检查添加以下约束,但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

我试图检查添加以下约束,但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))));

不幸的是,检查约束不能引用SYSDATE这样的函数。您需要创建一个触发器,在DML发生时检查这些值,即

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上插入或更新之前
每行
开始
如果(:new.CloseDate add_months(SYSDATE,12))
然后
引发应用程序错误(-20002,
“无效的关闭日期:关闭日期必须在下一年内-值=”||
to_char(:new.CloseDate,'YYYY-MM-DD HH24:MI:SS');
如果结束;

IF(:new.StartDate每次更新记录时,SYSDATE都会有一个不同的值。因此每次对约束的验证都会有所不同。Oracle因此不允许在约束中使用SYSDATE

您可以使用一个触发器来解决问题,该触发器检查CloseDate是否已实际更改,并在新值不在范围内时引发异常

和:什么是
(StartDate>(CloseDate+(SYSDATE+730))
?不能添加日期


并且:
StartDate
需要在
CloseDate
之后?这不奇怪吗?

您不能在check约束中使用SYSDATE。根据文件

无法设置检查约束的条件 包含以下构造:

  • 子查询和标量子查询表达式
  • 对非确定性函数的调用(当前日期,
    当前时间戳,DBTIMEZONE,
    LOCALTIMESTAMP,SESSIONTIMEZONE,
    SYSDATE、系统时间戳、UID、用户和 用户环境)
  • 对用户定义函数的调用
  • REF列的取消引用(例如,使用DEREF函数)
  • 嵌套表列或属性
  • 伪列CURRVAL、NEXTVAL、LEVEL或ROWNUM
  • 未完全指定的日期常量
有关10g第2版(10.2),请参阅;有关11g第2版(11.2)请参阅

请记住,完整性约束是关于表数据的语句,它总是true


无论如何:我不知道你到底想实现什么,但我认为你可以使用触发器来达到这个目的。

将sysdate写入一列并使用它进行验证。此列可能是您的审核列(例如:创建日期)


当你做这样一个小小的欺骗时,你可以做到这一点:

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 );
创建或替换函数SYSDATE\u确定性返回日期是确定性的
开始
返回系统日期;
结束系统日期;
/
创建表1(
s_日期,
生成的C_日期始终为(SYSDATE_DETERMINISTIC())
);
更改表1添加约束s_检查(s_日期
当然,函数
SYSDATE\u DETERMINISTIC
确定性的,但Oracle允许声明这一点


也许在未来的版本中,Oracle将变得更加智能,不再允许使用此类技巧。

我不建议使用触发器作为约束并引发异常,相反,您可以使用列将SYSDATE
存储为register date(如果您已经拥有它,则可以使用它)然后,您的约束将比较此列而不是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))));
更改表1
添加(注册日期);
创建或替换触发器训练检查日期
在表1上插入或更新之前
每行
开始
:new.REGISTER\u DATE:=SYSDATE;
结束;
更改表1
添加(约束GT\u表1\u关闭日期
检查(关闭日期>登记日期),
约束LT_表1_关闭日期
检查(关闭日期(关闭日期+(登记日期+730));
请注意,对于第二个“约束”LT\u Table1\u CloseDate,您可以在11g中使用虚拟列()
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 );
 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))));