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 列是根据表中国籍值计算的签证续签。
全名等在父表中未声明为唯一,因此您不能从子表中引用它们。
为什么需要在子表中复制这些列?
编辑:
锁定你的孩子表,你说:
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)
);
但如前所述,从规范化设计开始,看看是否有效
发生错误是因为您正在引用另一个表中不唯一的列。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 的一列或多列。