ORA-02270: 此列列表没有匹配的唯一键或主键

Sof*_*eer 6 oracle foreign-key oracle-11g

我收到以下错误报告:

错误报告 -
SQL 错误:ORA-02270:此列列表没有匹配的唯一键或主键
02270. 00000 - “此列列表没有匹配的唯一键或主键”
*原因:CREATE/ALTER TABLE 语句中的 REFERENCES 子句
           给出没有匹配的唯一或主要的列列表
           引用表中的键约束。
*操作:使用 ALL_CONS_COLUMNS 查找正确的列名
           目录视图

我能知道为什么吗?

父表

    CREATE TABLE STUDENTINFO
    (
      Student_ID VARCHAR2 (10) PRIMARY KEY,
      Full_Name VARCHAR2 (50) NOT NULL,
      Contact_Number NUMBER (15)NOT NULL,
      Address VARCHAR2 (50) NOT NULL,
      Nationality VARCHAR2 (15) NOT NULL,
      IC_PassportNo VARCHAR2 (15) NOT NULL,
      Programme VARCHAR (75) NOT NULL,
      Email_Address VARCHAR2 (50) NOT NULL REFERENCES                    USERNAMEPASSWORD(Username),
      Parents_Number NUMBER (15)NOT NULL,
      Fingerprint_Template clob
    );
Run Code Online (Sandbox Code Playgroud)

子表

    create table bit_2015_sep_cit4114_fyp_G_
    ( 
      Student_ID VARCHAR2 (10) PRIMARY KEY REFERENCES STUDENTINFO(Student_ID),
      Full_Name VARCHAR2 (50) NOT NULL REFERENCES STUDENTINFO(Full_Name),
      Nationality VARCHAR2 (15) NOT NULL REFERENCES STUDENTINFO(Nationality),
      Fingerprint_Template CLOB NOT NULL REFERENCES        STUDENTINFO(Fingerprint_Template),
     "23/10/2015" VARCHAR2 (15) not null, 
   );
Run Code Online (Sandbox Code Playgroud)

我将国籍和指纹保留为重复,因为根据studentinfo中存储的所有信息进行验证会很耗时,因此闯入个人班级会更容易和更快。就像表 STUDENTINFO 包含 100 万条记录,在表中 bit_2015_sep_cit4114_fyp_G_ 将只有 40 条记录。我保留国籍列是因为我的表结构中还有 1 列是根据表中国籍值计算的签证续签。

Len*_*art 6

全名等在父表中未声明为唯一,因此您不能从子表中引用它们。

为什么需要在子表中复制这些列?

编辑:

锁定你的孩子表,你说:

create table bit_2015_sep_cit4114_fyp_G_
( ...
, Full_Name VARCHAR2 (50) NOT NULL 
      REFERENCES STUDENTINFO(Full_Name)
Run Code Online (Sandbox Code Playgroud)

这意味着 STUDENTINFO 中必须有一个具有此全名的唯一行。即您需要声明该表:

CREATE TABLE STUDENTINFO
( ...
, Full_Name VARCHAR2 (50) NOT NULL
     UNIQUE,
Run Code Online (Sandbox Code Playgroud)

我怀疑 full_name 是唯一的,这意味着您不能针对此列声明外键。

您似乎认为稍后会出现性能问题,因此您对数据库进行了反规范化。IMO 这是一个很大的错误,从规范化的数据库开始,只有在有理由这样做时才去规范化。

如果您坚持去规范化,您可以使用以下技巧:

CREATE TABLE STUDENTINFO
( Student_ID VARCHAR2 (10) PRIMARY KEY
, Full_Name VARCHAR2 (50) NOT NULL
, Contact_Number NUMBER (15)NOT NULL
, Address VARCHAR2 (50) NOT NULL
, Nationality VARCHAR2 (15) NOT NULL
...
,    constraint AK1_STUDENTINFO unique (Student_ID, Full_Name, Nationality)
Run Code Online (Sandbox Code Playgroud)

由于Student_ID 是唯一的,因此Student_ID、Full_Name、Nationality 也必须是唯一的。我排除了 Fingerprint_Template ,因为我怀疑这是否可以用于外键(但不确定,如果可以,您可以添加它)

create table bit_2015_sep_cit4114_fyp_G_
( Student_ID VARCHAR2 (10) PRIMARY KEY
, Full_Name VARCHAR2 (50) NOT NULL 
, Nationality VARCHAR2 (15) NOT NULL
...
,    constraint fk_studentinfo foreign key (Student_ID, Full_Name, Nationality)
                references studentinfo (Student_ID, Full_Name, Nationality)
Run Code Online (Sandbox Code Playgroud)

);

但如前所述,从规范化设计开始,看看是否有效


ato*_*pas 6

发生错误是因为您正在引用另一个表中不唯一的列。Lennart 和 Balazs Papp 已经给出了很好的答案。

我想解释一下为什么我们需要父表中的唯一列。正如您所说,您希望在用于外键的列中保留重复值,这在创建表时是不可能的。但是您可以创建对包含重复值的现有表的引用。

如果您创建具有非唯一索引和NOVALIDATE选项的主键,则有可能。但这会导致令人困惑的结果。

让我解释一个情况。

我创建了一个包含一列的表,该列ID具有一个带有非唯一索引的主键约束。

SQL>CREATE TABLE t1(id NUMBER);
SQL>CREATE INDEX t1_index on t1(id);
SQL>INSERT INTO t1 VALUES(1);
SQL>INSERT INTO t1 VALUES(1);
SQL>COMMIT;
SQL>SELECT id FROM t1;

    ID
----------
     1
     1

SQL>ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (id) USING INDEX t1_index NOVALIDATE;
Run Code Online (Sandbox Code Playgroud)

让我们创建另一个表来引用第一个表。

SQL>CREATE TABLE t2(id NUMBER, CONSTRAINT t2_fk FOREIGN KEY(id) REFERENCES t1(id));
Run Code Online (Sandbox Code Playgroud)

生成一些记录。

SQL>INSERT INTO t2 VALUES(1);
SQL>COMMIT;
Run Code Online (Sandbox Code Playgroud)

t2有一个1引用父表的值,该父表t1的重复值为1。子表id将引用哪一个?

在上述场景中,外键工作正常,但表中的主键t1仅适用于新值。

结论: 外键必须始终引用在 Oracle 中声明为 PRIMARY KEY 或 UNIQUE 的一列或多列。