2011-12-08 88 views
4

我正在Oracle中創建我的員工表併爲emp_date創建我想讓它的出生日期不會回到過去,並且不能在將來設置?CHECK約會出生日期?

這是否太複雜,無法在CREATE TABLE語句中實現?如果是這樣,那麼我想我必須跳過它,因爲那是我必須創建約束的部分。

, emp_dob DATE NOT NULL 

    CREATE TABLE employee(emp_id NUMBER(4) PRIMARY KEY 
, emp_name VARCHAR2(40) NOT NULL 
, emp_address VARCHAR2(60) NOT NULL 
, emp_tel NUMBER(11) NOT NULL 
, CONSTRAINT emp_tel_length CHECK (LENGTH(emp_tel) BETWEEN 9 and 11) 
, emp_dob DATE NOT NULL 
, CONSTRAINT check_date_of_birth CHECK (emp_dob BETWEEN DATE '1950-01-01' AND sysdate)) 

回答

9

檢查約束必須是確定性的。也就是說,一個特定的行必須總是滿足約束,否則它總是不能滿足約束。但SYSDATE本質上是非確定性的,因爲返回的值不斷變化。因此,您無法定義調用SYSDATE或任何其他用戶定義函數的約束條件CHECK

如果試圖在約束定義引用SYSDATE,你會得到一個錯誤

SQL> ed 
Wrote file afiedt.buf 

    1 create table t(
    2  birth_date date check(birth_date between date '1900-01-01' and 
    3            sysdate) 
    4*) 
SQL>/
               sysdate) 
               * 
ERROR at line 3: 
ORA-02436: date or system variable wrongly specified in CHECK constraint 

您可以創建一個CHECK約束其中兩個最小和最大的日期被硬編碼,但是這不會是特別實用,因爲你必須不斷地刪除和重新創建約束。

SQL> ed 
Wrote file afiedt.buf 

    1 create table t(
    2  birth_date date check(birth_date between date '1900-01-01' and 
    3             date '2011-12-08') 
    4* ) 
SQL>/

Table created. 

強制執行這種要求是,在表上創建一個觸發器

CREATE OR REPLACE TRIGGER check_birth_date 
    BEFORE INSERT OR UPDATE ON employee 
    FOR EACH ROW 
BEGIN 
    IF(:new.emp_dob < date '1900-01-01' or 
     :new.emp_dob > sysdate) 
    THEN 
    RAISE_APPLICATION_ERROR( 
     -20001, 
     'EMployee date of birth must be later than Jan 1, 1900 and earlier than today'); 
    END IF; 
END; 
+0

非常有趣和有用的分析。 –

2

另一種方法是創建一個域名birthdate,並在域中建立約束。這將允許您在其他表定義中重用相同的類型。

CREATE DOMAIN birthdate AS date DEFAULT NULL 
    CHECK (value >= '1900-01-01' AND value <= now()) 
    ; 

CREATE TABLE employee 
    (empno INTEGER NOT NULL PRIMARY KEY 
    , dob birthdate NOT NULL 
    ... 
    ); 
+0

不幸的是,Oracle不支持'CREATE DOMAIN'聲明。 –

+0

嗯,我不知道。對於oracle用戶來說真的很痛苦,因爲它會迫使他們使用類型或表格作爲域名,甚至爲了模擬域名而創建醜陋的觸發器(見下文)。 – wildplasser

1

什麼其他解決辦法

寫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