oracle 如何拥有可能具有空值的主键组合?

cs7cruho  于 2023-04-20  发布在  Oracle
关注(0)|答案(4)|浏览(236)

我有两个表A和B定义如下。

create table A
(
  A_1 varchar2(10) NOT NULL,
  A_2 varchar2(10),
  A_3 varchar2(10),
  constraint A_PK primary key (A_1,A_2)
)
TABLE A DATA
A_1      |A_2   |A_3
1111     abc     some_text1
1111     null    some_text1
1112     abc     some_text2
1113     def     some_text3

   create table B
   (
     B_1 varchar2(10) NOT NULL,
     B_2 varchar2(10),
     B_3 varchar2(10),
     constraint B_PK primary key (B_1,B_2,B_3),
     constraint B_FK foreign key (B_1,B2) references A(A_1,A_2)
   )
TABLE B DATA
B_1    | B_2    |B_3
1111    abc      text1
1111    null     text2
1111    null     text3
1111    null     text4

表A中的A_2列有时可能为空,但A_1和A_2的组合始终是唯一的。我需要A_2是主键的一部分,因为只有这样我才能引用A_1和A_2,它们作为表B中的外键。这里的问题是主键不能为空。如何解决这个问题?任何回应都将受到高度赞赏

ocebsuys

ocebsuys1#

解决这个问题的方法是不使用this作为主键。主键不能是NULL,或者如果它们是复合主键,则不能包含NULL。请将其改为唯一索引。为主键创建一个自动编号字段。

9w11ddsr

9w11ddsr2#

主键中不能有null列,但可以创建一个包含null列的Unique索引。为了让它在Oracle 10 g中工作,我还必须在表中显式添加一个unique constraint:

create table t1 (a1 integer not null,
                 a2 integer,
                 a3 integer);

create unique index t1_uk1 on t1(a1, a2);

alter table t1 add constraint t1_cuk1 unique (a1, a2);

create table b1 (b1 integer not null, b2 integer, b3 integer);

create index b1_idx1 on b1 (b1, b2);

alter table b1 add constraint b1_fk1 
  foreign key (b1, b2) references t1 (a1, a2);

然而,我试着测试这个设置,它并不像我预期的那样工作。例如:

SQL> insert into t1 values (1, null, 1);

1 row created.

SQL> insert into b1 values (1, 1, 1);
insert into b1 values (1, 1, 1)
*
ERROR at line 1:
ORA-02291: integrity constraint (B1_FK1) violated - parent key not
found

好了,这就是我们所期望的。父表中没有行,所以子表中不允许有行,但是:

SQL> insert into b1 values (2, null, 1);

1 row created.

看起来它只是让该行被插入而没有失败,即使t1中根本没有2,null的行!

SQL> commit;

Commit complete.

SQL> select * from t1;

        A1         A2         A3
---------- ---------- ----------
         1                     1

SQL> select * from b1;

        B1         B2         B3
---------- ---------- ----------
         2                     1

我对这种行为感到惊讶,因为t1上的唯一索引的行为与您所期望的一样(只能插入1行,1,null等)。

ioekq8ef

ioekq8ef3#

如果你在主键上使用“deferable initial deferred”,你可以有NULL值...

u7up0aaq

u7up0aaq4#

从技术上讲,你可以创建一个复合主键,其中一部分被标记为可空。你也可以从另一个表中引用它,并使它成为其复合主键的一部分。
以下语句在Oracle中是合理的:

create table A
(
  A_1 varchar2(10) NOT NULL,
  A_2 varchar2(10) NULL,
  A_3 varchar2(10),
  constraint A_PK primary key (A_1,A_2)
)

create table B
(
  B_1 varchar2(10) NOT NULL,
  B_2 varchar2(10) NULL,
  B_3 varchar2(10),
  constraint B_PK primary key (B_1,B_2,B_3),
  constraint B_FK foreign key (B_1,B_2) references A(A_1,A_2)
)

您也可以在上述表格中插入值。
但是,由于primary key约束的存在,您仍然不能在A_2B_2中插入空值。
在标记为null的列上设置primary key和在标记为not null的列上设置primary key之间有一个核心区别。
在后一种情况下,如果禁用primary key(通过使用:ALTER TABLE A DISABLE PRIMARY KEY;),您仍然有一个check constraint存在(对于每个不可空的列),这将防止空插入。

相关问题