2010-07-30 5 views
6

여러 열에 하나의 값을 가질 수 있지만 null (또는 상수 값)이 아닌 복합 키를 만들려면 어떻게해야합니까? 예를 들어여러 열에 복합 키를 만드는 방법

: 네번째 기록

PK Loc_ID  Date    Time  Cancelled 
1   1   01/01/2010  10:00AM  YES 
2   1   01/01/2010  10:00AM  YES 
3   1   01/01/2010  10:00AM  null 
4   1   01/01/2010  10:00AM  null - Not Acceptable 

삽입 복합 키 위반 오류가 발생한다.

+3

귀하의 예를 그들이 널 않는 한 그래서 지수가 취소됨의 중복 값을 허용 데이터는 PK = 2 인 행을 거부하지 않을 경우 PK = 4 행을 거부 할 근거가 없습니다. –

+0

@Jonathan Leffler - 이길 수 있습니다. 같은 질문이있었습니다. – Thomas

+0

예, PK = 2는 정상입니다. 취소 된 값은 같지만 동일한 locid, 날짜 및 시간에 대해 두 번 반복되는 null이 아닌 값을 가질 수 있습니다. –

답변

6

그래서 당신은 단지 기록이 LOC_ID, 날짜, 시간의 주어진 순열 취소 할 수없는 규칙을 적용 할 것입니다 무엇? 함수 기반 고유 인덱스를 사용하여이를 수행 할 수 있습니다.

SQL> select * from t34 
    2/

     PK  LOC_ID SOMEDATE SOMETIM CAN 
---------- ---------- ---------- ------- --- 
     1   1 01/01/2010 10:00AM YES 
     2   1 01/01/2010 10:00AM YES 
     3   1 01/01/2010 10:00AM 

SQL> insert into t34 
    2 values (4 , 1 , to_date('01/01/2010','DD/MM/YYYY') , '10:00AM', null) 
    3/

1 row created. 

SQL> 

이의 규칙을

SQL> rollback 
    2/

Rollback complete. 

SQL> create unique index t34_uidx 
    2 on t34 (loc_id, somedate, some_time, nvl2(cancelled, pk, null)) 
    3/

Index created. 

SQL> 

NVL2() 기능을 적용 할 인덱스를 구축하자의 경우 두 번째 인수를 반환 CASE의 특별한 형태입니다 :

은 우리가 피하고 싶은 것입니다 첫 번째 인수는 NOT NULL이며 세 번째 인수는 NOT NULL입니다. 이 인덱스는 기본 키이므로 고유하므로 PK col을 두 번째 인수로 사용합니다.

SQL> insert into t34 
    2 values (4 , 1 , to_date('01/01/2010','DD/MM/YYYY') , '10:00AM', null) 
    3/
insert into t34 values (4 , 1 , to_date('01/01/2010','DD/MM/YYYY') , '10:00AM', null) 
* 
ERROR at line 1: 
ORA-00001: unique constraint (APC.T34_UIDX) violated 


SQL> 
+0

와우! 이 작동합니다. 감사. –

0

나는이 오라클에서 유효 모르겠지만, PostgreSQL을에 당신이 null 인 컬럼을 제외하고, 널 (null)에 부분 멀티 컬럼 인덱스를 사용하여이 작업을 수행 할 수 있습니다.

CREATE UNIQUE INDEX idx_foo 
ON example (Loc_ID, Date, Time) 
WHERE canceled IS NULL 
+0

아니요,'row2'는'cancelled' IS NOT NULL입니다. 이것은 NULL의 부분 색인입니다. 나는 당신이 오라클에서 이것을 할 수 있음을 확신합니다. 나는 어떻게 해야할지 모르며, 대답에 더할 나위없이 좋을 것이라고 생각했습니다. –

+0

오른쪽. 알았다. 나는 SQL 2008이이 개념을지지한다고 생각하지만 나는 오라클이 아직 그렇게 생각하지 않는다. – Thomas

+0

저는 이것이 아마도 SQL 99라고 생각하지 않습니다. PostgreSQL은 적어도 8 년간 지원해 왔습니다. –

1

고유 한 기능 기반 색인으로이 작업을 수행 할 수 있습니까? 같은 뭔가 :

create unique index ix on tb (
    loc_id, date, time, decode(cancelled, null, 1, null)); 
+0

은 loc_id, date의 동일한 조합에 대해 '예'인 경우 오라클에서 작동하지 않을 것이다. , 시각. –

+0

APC의 버전이 nvl2()가 더 깨끗하고 명확하게 작동하지만 테스트되지 않았습니다.내 자신만을 위해서, 나는 같은 의도에 관한 null을 효과적으로 뒤집을 것이다. 하지만 아마도'decode (cancelled, null, , pk)'를 수행 했어야합니다. 마법의 가치가 무엇이든간에 'pk'는 절대 존재하지 않을 것입니다. 어느 것이 그 자체로 명백하게 위험한 ... 그래서 –

1

규칙이 하나의 NULL이 LOC_ID, DATE_COL 및 TIME_COL의 특정 조합에 대한 값을 취소한다는 것입니다 경우 :

SQL> create table EXAMPLE 
    2 ( PK  number  not null, 
    3  LOC_ID number  not null, 
    4  DATE_COL date   null, 
    5  TIME_COL varchar2(10) null, 
    6  CANCELLED varchar2(3) null, 
    7  constraint EXAMPLE_PK primary key (PK) 
    8 ); 

Table created. 

SQL> 
SQL> create unique index EXAMPLE_UK01 on EXAMPLE 
    2 (case when CANCELLED is null then LOC_ID else null end, 
    3  case when CANCELLED is null then DATE_COL else null end, 
    4  case when CANCELLED is null then TIME_COL else null end 
    5 ); 

Index created. 

SQL> 
SQL> INSERT INTO EXAMPLE VALUES 
    2 (1, 1, DATE '2010-01-01', '10:00AM', 'YES'); 

1 row created. 

SQL> 
SQL> INSERT INTO EXAMPLE VALUES 
    2 (2, 1, DATE '2010-01-01', '10:00AM', 'YES'); 

1 row created. 

SQL> 
SQL> INSERT INTO EXAMPLE VALUES 
    2 (3, 1, DATE '2010-01-01', '10:00AM', null); 

1 row created. 

SQL> 
SQL> INSERT INTO EXAMPLE VALUES 
    2 (4, 1, DATE '2010-01-01', '10:00AM', null); 
INSERT INTO EXAMPLE VALUES 
* 
ERROR at line 1: 
ORA-00001: unique constraint ([schema].EXAMPLE_UK01) violated 
관련 문제