2012-01-22 3 views
0

내가 원하는 것은 간단하며 아래에 세부 사항이 있습니다. 나는 두 개의 테이블을 가지고있다.Oracle Sql Check Constraint

Create Table Event(
IDEvent number (8) primary key, 
StartDate date not null, 
EndDate date not null 
); 

괜찮습니다.

다음은 두 번째 표입니다.

Create Table Game(
IDGame number (8) primary key, 
GameDate date not null, 
constraint checkDate 
check (GameDate >= to_date(StartDate references from Event(StartDate))) 
); 

제한 조건 checkDate는 날짜가 시작 날짜보다 큰지 확인하는 것입니다. 확인하는 동안 오류가 발생했습니다 : Missing right parenthesis.

내 질문에, 이것이 가능하다면 왜 나에게 오류가 발생합니까?

+1

그래서'StartDate'가'GameDate'와 비교하기를 원하는'Event'에 5 개의 레코드가 있다면? –

답변

4

테이블의 점검 제한 조건은 해당 테이블의 컬럼 조건 만 검증 할 수 있습니다. 다른 테이블의 열은 참조 할 수 없습니다.

다른 테이블의 열과 관련된 조건을 확인해야하는 경우 해당 테이블의 삽입/업데이트 트리거 이전에 수행 할 수 있습니다.

+0

그래, 방아쇠가 필요해 :(설명해 주셔서 감사합니다 Raihan – P3druh77

0

당신이하고 싶은 일은 단순하지 않습니다.

제안하는 구문은 모든 RDBMS에서 작동하지 않습니다. 이런 크로스 테이블 무결성 규칙을 적용하면 게임 테이블을 업데이트하는 동안 참조 된 테이블을 잠그는 것이므로 RDBMS 공급 업체 중 누구도 구현하지 않은 것이 좋을 것입니다. 직접 제작하려고한다면 스스로 잠금을해야합니다. 당신이 고려해야 할 것 같은 규칙을 위반 아마도 수있는 모든 조치 :

  • 이 이상으로 이벤트 STARTDATE를 업데이트 덜 최근 날짜
  • 에 gamedate를 업데이트 게임
  • 를 삽입 이벤트

그리고 당신은 다른 테이블에 올바른 기록을 잠금으로써, 다중 사용자 증거입니다 코드를 작성하는 생각해야합니다 이러한 작업의 각을 삭제 최근 날짜

  • .

    이 복잡성을 줄이려면, 당신은 RuleGen라는 제품을보고 할 수 있습니다 (www.rulegen.com)

    또는 특정 API를 구축하고자 그냥 오른쪽 검사를 포함 할 수있다 장소. 이 시나리오에서는 수동으로 스스로 잠 가야합니다.

    희망이 도움이됩니다.

    감사합니다.
    Rob.

  • 0

    이 당신이 할 수있는 하나의 해킹,하지만 난 테이블이 특정 크기로 성장하면, 허용 될 것 삽입 게임이나 이벤트의 성능을 의심 : 게임을 삽입 이제

    CREATE TABLE Event 
    (
        IDEvent  NUMBER(8) PRIMARY KEY, 
        StartDate DATE NOT NULL, 
        EndDate  DATE NOT NULL 
    ); 
    
    CREATE TABLE Game 
    (
        IDGame  NUMBER(8) PRIMARY KEY, 
        GameDate DATE NOT NULL, 
        eventid NUMBER(8), -- this is different to your table definition 
        CONSTRAINT fk_game_event FOREIGN KEY (eventid) REFERENCES event (idevent) 
    ); 
    
    CREATE INDEX game_eventid ON game (eventid); 
    
    CREATE MATERIALIZED VIEW LOG ON event 
        WITH ROWID, SEQUENCE (idevent, startdate) INCLUDING NEW VALUES; 
    
    CREATE MATERIALIZED VIEW LOG ON game 
        WITH ROWID, SEQUENCE (idgame, eventid, gamedate) INCLUDING NEW VALUES; 
    
    CREATE MATERIALIZED VIEW mv_event_game 
    REFRESH FAST ON COMMIT WITH ROWID 
    AS 
    SELECT ev.idevent, 
         ev.startdate, 
         g.gamedate 
    FROM event ev, game g 
    WHERE g.eventid = ev.idevent; 
    
    ALTER TABLE mv_event_game 
        ADD CONSTRAINT check_game_start check (gamedate >= startdate); 
    

    트랜잭션 다시

    Connected to: 
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production 
    With the Partitioning and OLAP options 
    
    SQL> INSERT INTO event 
        2 (idevent, startdate, enddate) 
        3 values 
        4 (1, date '2012-01-22', date '2012-01-24'); 
    
    1 row created. 
    
    SQL> 
    SQL> INSERT INTO game 
        2 (idgame, eventid, gamedate) 
        3 VALUES 
        4 (1, 1, date '2012-01-01'); 
    
    1 row created. 
    
    SQL> commit; 
    commit 
    * 
    ERROR at line 1: 
    ORA-12008: error in materialized view refresh path 
    ORA-02290: check constraint (FOOBAR.CHECK_GAME_START) violated 
    

    :하지만이 에 삽입 할 것 트랜잭션을 커밋 하려고 할 때이 오류가 발생합니다 참조 된 이벤트 전에 시작 두 테이블 모두 커밋이 수행 될 때마다 mview 내부의 쿼리를 실행해야하므로 속도가 느려집니다.

    새로 고침 유형을 FAST으로 변경할 수 없어 커밋 성능이 향상 될 수 있습니다.

    +0

    이것은 현명한 성과가 아닙니다. 동시 업데이트 중에 추가로 경합을 일으킬 것입니다 (http://rwijk.blogspot.com/2010/01/enq- jl-contention.html). rowid를 조인 mv에 추가 할 때 구체화 된 뷰를 빠르게 새로 고칠 수 있습니다. 새 값 포함은 필요하지 않음. –

    +0

    @RobvanWijk : 빠른 새로 고침에 대한 힌트를 주셔서 감사합니다. 내 시도 중 하나에 rowids (하지만 로그되었을 수도 있습니다) –