2010-04-23 2 views
5

2 개의 열, a (고유 한) 및 b가있는 테이블이 열 b가 열 a의 임의의 값과 동일한 레코드를 갖지 못하도록하는 좋은 방법은 무엇입니까? 이 바람직 할 것이다 트리거 및 더 동시 활동을 가정하지 하위 쿼리하지만 더 선언적 접근 할 수있는 방법을 내가 볼 수Oracle에서 모든 열과 동일한 값을 포함하는 열 b를 방지하는 방법은 무엇입니까?

MR -> Mr 
Prf. -> Prof. 
MRs -> Mrs 

, 이런 수정의 테이블에 대해 사용됩니다.

Wing Commdr. -> Wing Cdr. 
Wing Cdr. -> Wing Commander 

이상적 솔루션이 동시 삽입 및 업데이트와 함께 일하는 것이 방지 될해야하는지의 예입니다.

+0

열 A는 테이블에서 고유해야합니까? – dpbradley

+0

예, 열 A에는 고유성이 적용되어야합니다. –

답변

2

요구 사항을 적용하기 위해 구체화 된보기를 사용할 수 있습니다 (10.2.0.1에서 테스트 됨).

SQL> CREATE TABLE t (a VARCHAR2(20) NOT NULL PRIMARY KEY, 
    2     b VARCHAR2(20) NOT NULL); 
Table created 

SQL> CREATE MATERIALIZED VIEW LOG ON t WITH (b), ROWID INCLUDING NEW VALUES;  
Materialized view log created 

SQL> CREATE MATERIALIZED VIEW mv 
    2  REFRESH FAST ON COMMIT 
    3 AS 
    4 SELECT 1 umarker, COUNT(*) c, count(a) cc, a val_col 
    5 FROM t 
    6 GROUP BY a 
    7 UNION ALL 
    8 SELECT 2 umarker, COUNT(*), COUNT(b), b 
    9 FROM t 
10 GROUP BY b;  
Materialized view created 

SQL> CREATE UNIQUE INDEX idx ON mv (val_col);  
Index created 

고유 색인을 사용하면 두 열 (두 행)에서 동일한 값을 가질 수 없습니다.

SQL> INSERT INTO t VALUES ('Wing Commdr.', 'Wing Cdr.');  
1 row inserted 

SQL> COMMIT;  
Commit complete 

SQL> INSERT INTO t VALUES ('Wing Cdr.', 'Wing Commander');  
1 row inserted 

SQL> COMMIT;  

ORA-12008: erreur dans le chemin de régénération de la vue matérialisée 
ORA-00001: violation de contrainte unique (VNZ.IDX) 

SQL> INSERT INTO t VALUES ('X', 'Wing Commdr.');  
1 row inserted 

SQL> COMMIT; 

ORA-12008: erreur dans le chemin de régénération de la vue matérialisée 
ORA-00001: violation de contrainte unique (VNZ.IDX) 

만 열 A와 B의 값에 위탁 중에 직렬화 (즉 일반에 동시 분리 된 활성을 방지 안된다).

유니티는 COMMIT 시간에만 검사되며 일부 도구는 커밋이 실패 할 것으로 예상하지 않으며 부적절하게 행동 할 수도 있습니다. 또한 COMMIT가 실패하면 전체 트랜잭션이 롤백되고 사용자는 커밋되지 않은 변경 사항을 잃게됩니다 ("재 시도"할 수 없음).

+0

이 솔루션은 무결성 책임을 인덱스로 푸시하기 때문에이 솔루션이 마음에 들었습니다. –

0

세션 A 삽입 ('A', 'B')을 수행하지만 커밋하지 않은 경우 세션 B는 커밋하지 않고 삽입합니다 ('B', 'A'). 어떤 세션도 다른 세션에서 삽입 한 레코드를 볼 수 없습니다. 그런 다음 세션이 커밋됩니다.

한 세션이 삽입 (BEFORE INSERT 트리거) 될 때 전체 테이블을 잠그고 AFTER INSERT 트리거에서 검사를 수행하여 직렬화 할 수 있습니다. 테이블에 지정한 내용이있는 경우 많은 활동이 표시되어서 직렬화가 문제가되지 않습니다.