如何在多个列上创建复合键,其中一个列可以有一些值但不是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
插入第四条记录会引发复合键违规错误。
答案 0 :(得分:6)
那么你要用什么来强制执行一条规则,其中只有LOC_ID,DATE,TIME的任何给定排列都不能取消记录?我们可以使用基于函数的唯一索引来完成此任务。
这是我们想要避免的:
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,则返回第二个参数,否则返回第三个参数。索引使用PK col作为第二个参数,因为它是主键,因此是唯一的。所以索引允许重复值为CANCELED,除非它们为null:
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>
答案 1 :(得分:1)
可以使用基于函数的唯一索引来完成吗?类似的东西:
create unique index ix on tb (
loc_id, date, time, decode(cancelled, null, 1, null));
答案 2 :(得分: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
答案 3 :(得分:0)
我不确定它在Oracle中是否有效,但是在Postgresql中,你可以使用null的部分多列索引来做到这一点,不包括null的列。
CREATE UNIQUE INDEX idx_foo
ON example ( Loc_ID, Date, Time )
WHERE canceled IS NULL