web-dev-qa-db-ja.com

チェック制約で日付を使用する、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.
9
Jon

残念ながら、チェック制約は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;
16
Justin Cave

チェック制約でSYSDATEを使用することはできません。ドキュメントによると

チェック制約の条件には、次の構成を含めることはできません。

  • サブクエリとスカラーサブクエリ式
  • 決定論的ではない関数の呼び出し(CURRENT_DATE、
    CURRENT_TIMESTAMP、DBTIMEZONE、
    LOCALTIMESTAMP、SESSIONTIMEZONE、
    [〜#〜] sysdate [〜#〜]、SYSTIMESTAMP、UID、USER、およびUSERENV)
  • ユーザー定義関数の呼び出し
  • REF列の逆参照(たとえば、DEREF関数を使用)
  • ネストされたテーブルの列または属性
  • 疑似列CURRVAL、NEXTVAL、LEVEL、またはROWNUM
  • 完全に指定されていない日付定数

10gリリース2(10.2)については、 制約 を参照してください。11gリリース2については、 (11.2)制約 を参照してください。

整合性制約は、常にtrueであるテーブルデータに関するステートメントであることを忘れないでください。

とにかく:あなたが何を達成しようとしているのか正確にはわかりませんが、この目的のためにトリガーを使用できると思います。

15

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
5
SriniV

レコードが更新されるたびに、SYSDATEの値は異なります。したがって、制約は毎回異なる方法で検証されます。そのため、Oracleでは制約にsysdateを使用できません。

CloseDateが実際に変更されたかどうかをチェックし、新しい値が範囲内にない場合は例外を発生させるトリガーを使用して、問題を解決できる場合があります。

そして:(StartDate > (CloseDate + (SYSDATE + 730))))とは何ですか?日付を追加することはできません。

そして:StartDateCloseDateである必要がありますか?それは変ではないですか?

5
Jeff

あなたがこのように少しチートをするとき、あなたはこれを達成することができます:

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 is not deterministicですが、Oracleではとにかくこれを宣言できます。

おそらく将来のリリースでは、Oracleはよりインテリジェントになり、そのようなトリックは許可されなくなります。

1

トリガーを制約として歌ったり、例外を発生させたりすることはお勧めしません。代わりに、列を使用して[〜#〜] 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))));
0
hmmftg