2011-03-16 71 views
5

我想檢查添加以下約束,但Oracle返回下面顯示的錯誤。在檢查約束中使用日期,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 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. 

回答

11

檢查約束,遺憾的是,不能引用像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

注意,對於第二個「約束」 LT_Table1_CloseDate,您可以使用在使用虛擬列11g的一個檢查約束(http://rwijk.blogspot.com/2007/12/check-約束與 - sysdate.html) – 2011-03-17 08:43:32

4

每一次記錄更新SYSDATE都會有不同的價值。因此,約束每次都會有不同的驗證。出於這個原因,Oracle不允許sysdate存在約束。

您可以通過觸發器來解決問題,該觸發器檢查CloseDate是否實際更改,並在新值不在範圍內時引發異常。

而且:什麼是(StartDate > (CloseDate + (SYSDATE + 730))))?你不能添加日期。

And:StartDate需要CloseDate?這不奇怪嗎?

11

您不能在檢查約束中使用SYSDATE。據文檔

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

對於10第2版(10.2),見constraint,11g第2版(11.2)看到constraint

請記住,完整性約束是關於表格數據的說明,它是總是爲真。

無論如何:我並不確切知道你在努力達成什麼目標,但我認爲你可以使用觸發器達到此目的。

3

將sysdate寫入列並將其用於驗證。此列可能是您的審計列(如:創建日期)

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

,當你做一個小騙子這樣你就可以做到這一點:

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_DETERMINISTIC確定性的,但Oracle允許聲明這一點。

也許在未來的版本中,Oracle變得更加智能化,不再允許這樣的技巧。

0

我不`噸推薦唱觸發器爲約束,提高例外,相反,你可以使用列存儲SYSDATE的報到日期(如果你已經擁有了它,那麼你可以使用它),然後你的約束比較該列而不是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))));