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