条件唯一约束 SQL

Conditional Unique Constraint SQL

有没有办法在给定条件为真时忽略唯一约束?

例如,我的数据库中有 3 列构成了唯一约束:

create table example_table
  (
    column_primarykey RAW(16) default NULL not null,
    column_a number(8) not null,
    column_b number(8) not null,
    column_c number(8) not null,
    constraint constraint_1
          unique(column_a, column_b, column_c)
    constraint constraint_2
          primary key (column_primarykey)

现在我添加第四列:

alter table example_table
      add column_d number(8) not null,

我想要实现的是,如果 column_d 的值已经存在于 table 中,那么唯一约束将被忽略。如果 column_d 在 table 中不是唯一的,则忽略唯一约束,您可以将行添加到 table。例如,这是我 table 中的现有数据(忽略主键原因不相关):

column_a column_a column_c column_d
1 2 3 1
3 4 5 2

我想要的是您可以添加例如 (1, 2, 3, 1) 但不能添加 (1, 2, 3, 2),因为已经有包含前三个值的行。仅当 column_d 中的值已经存在并且其他值等于现有行时才可能。

更多有助于理解的示例:

Example insert result reason
(1, 2, 3, 1) accepted d is not unique and a, b, c got same values as the existing row with value 1 for column_d
(1, 2, 3, 4) rejected a, b ,c exists already in the table
(5,6,7,1) rejected 1 exists but with different values for a b and c
(3,4,5, 2) accepted d exists and a, b, c, have the same values
(7,8,9,3) accepted a, b, c are unique and d does not exist

听起来您试图将两个或更多 table 压缩为一个 table。

  • 没有更多的背景很难说

例如,如果您制作了一个大的平面文件,您可能会有这个?

a b c d x y z
1 2 3 1 1 3 1
1 2 3 1 2 8 7
1 2 3 1 5 9 2
4 5 6 2 9 8 7
4 5 6 2 4 5 6
4 5 6 2 3 2 1
4 5 6 2 2 1 0

虽然数据库不是电子表格或平面文件,但它们是关系结构。

上面的文件在数据库中可能会更好地表示为两个 tables...

a b c d
1 2 3 1
4 5 6 2
d x y z
1 1 3 1
1 2 8 7
1 5 9 2
2 9 8 7
2 4 5 6
2 3 2 1
2 2 1 0

如果你想要一行新的“数据”,你可以在第二行中添加一行table。

如果要在 (a,b,c)(d) 之间创建新关系,请向第一个 table 添加一行。


可以按如下方式实施和强制执行...

CREATE TABLE map (
    column_a       NUMBER(8) NOT NULL,
    column_b       NUMBER(8) NOT NULL,
    column_c       NUMBER(8) NOT NULL,
    column_d       NUMBER(8) NOT NULL,
    UNIQUE(column_a, column_b, column_c),
    UNIQUE(column_d)
)

CREATE TABLE fact (
    column_pk      RAW(16)   NOT NULL,
    column_d       NUMBER(8) NOT NULL,
    column_x       NUMBER(8) NOT NULL,
    column_y       NUMBER(8) NOT NULL,
    column_z       NUMBER(8) NOT NULL,
    PRIMARY KEY (column_pk),
    FOREIGN KEY (column_d) REFERENCES map(column_d)
)

据我所知,这个结构可以包含您想要允许的所有内容,以及禁止您想要禁止的所有内容。

据我了解,您有两个独特的约束(在 A,B,CD 上),如果在 A,B,C,D.[=19 上有重复项,您希望同时抑制这两个约束=]

这是 AFAIK 不可能在一个 table 中完成的,因此您必须将您的设置分成两个 table。

第一个 ABCD 检查约束,但不允许重复,第二个 TAB 存储实际数据并引用第一个 table。

插入触发器 中,A,B,C,D 上的唯一值在第一个 table 中 合并

create table abcd
(a int,
 b int,
 c int,
 d int,
 constraint abcd unique (a,b,c,d),
 constraint abc unique (a,b,c),
 constraint d unique(d));

drop  table tab;
create table tab
(pk int,
 a int,
 b int,
 c int,
 d int, 
 primary key(pk),
 foreign key(a,b,c,d) references abcd(a,b,c,d)
 );
 
CREATE OR REPLACE TRIGGER tab_trigger
  BEFORE  INSERT ON tab
  FOR EACH ROW
BEGIN
   merge into abcd using
   (select  :new.a a, :new.b b, :new.c c, :new.d d from dual) src
    on  (abcd.a = src.a and abcd.b = src.b and abcd.c = src.c and abcd.d = src.d)
    when not matched then insert (a,b,c,d) values (src.a, src.b, src.c, src.d)
    ;
END;
/

测试按预期运行

insert into tab(PK, A, B, C, D) values (1, 1,2,3,1);
1 row inserted.
insert into tab(PK, A, B, C, D) values (2, 3,4,5,2);
1 row inserted.
insert into tab(PK, A, B, C, D) values (3, 1,2,3,1);
1 row inserted.
insert into tab(PK, A, B, C, D) values (4, 1,2,3,4);
ORA-00001: unique constraint (ZZZ.ABC) violated
insert into tab(PK, A, B, C, D) values (5, 5,6,7,1);
ORA-00001: unique constraint (ZZZ.D) violated
insert into tab(PK, A, B, C, D) values (6, 3,4,5,2);
1 row inserted.
insert into tab(PK, A, B, C, D) values (7, 7,8,9,3);
1 row inserted.

无论如何我必须承认我不喜欢基于触发器的解决方案,我更喜欢带有检查视图的延迟验证.

即您可以插入任何行,但在视图中您会看到哪些行无效并且您可以处理它。

验证查询相当简单,它使用分析函数来获取键的重复计数

with abcd as (
select PK, A, B, C, D,
count(*) over (partition by A, B, C order by  PK) cnt_abc,
count(*) over (partition by D order by  PK) cnt_d,
count(*) over (partition by A, B, C, D order by PK) cnt_abcd
from tab)
select
   PK, A, B, C, D, CNT_ABC, CNT_D, CNT_ABCD,
   case when (CNT_ABC > 1 or CNT_D > 1) and CNT_ABCD = 1 then 'rejected' 
   else 'accepted' end as status
from abcd   
order by PK;

        ID          A          B          C          D    CNT_ABC      CNT_D   CNT_ABCD STATUS  
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
         1          1          2          3          1          1          1          1 accepted
         2          3          4          5          2          1          1          1 accepted
         3          1          2          3          1          2          2          2 accepted
         4          1          2          3          4          3          1          1 rejected
         5          5          6          7          1          1          3          1 rejected
         6          3          4          5          2          2          2          2 accepted
         7          7          8          9          3          1          1          1 accepted