2011-12-08 17 views
4

私はオラクルに従業員テーブルを作成しています。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を参照しようとした場合、あなたはあなたが最小値と最大値の日付の両方がハードコードされた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            sysdate) 
    4*) 
SQL>/
               sysdate) 
               * 
ERROR at line 3: 
ORA-02436: date or system variable wrongly specified in CHECK constraint 

を得るでしょうが、それはないだろうあなたが絶えず制約を削除して再作成する必要があるので、特に実用的です。

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

もう1つの方法は、ドメインに組み込まれた制約を使用して、ドメインの誕生日を作成することです。これにより、他のテーブル定義で同じタイプを再利用することができます。

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