Oracle Partial Foreign Key不是唯一的

时间:2014-07-10 11:03:16

标签: oracle oracle11g foreign-keys triggers

你好古人的互联网!

今天我在使用Oracle Foreign Composite键时遇到了一些问题。我有一个有点大的应用程序(你知道,5000多个表,那种东西),我们存储一些静态的' (它实际上可以改变)数据到一组表中。许多表通过数据库引用了这些数据,所以它的工作原理如下:

TABLE StaticData 
ID(PK)  Data    
1       StaticData1
2       StaticData2
...
n       StaticDataN

TABLE TypicalTable
ID(PK)  StaticDataID(FK to StaticData)  
1       1
2       1
3       7
4       2
...
n       n

仙境中一切都很好。

但是规范的一些变化,以及之后与客户的一些会议,我们的任务是拥有不同的版本'当一些时间到来时,数据准备好替换静态数据。最后一部分很简单,我们可以创建将每天/每周检查日期并更改数据的作业,但我们必须在同一个表中维护较新版本的数据。所以现在StaticData看起来像:

TABLE StaticData 
ID(PK)  Data            KickInDate(Also PK)
1       StaticData1.1       01/01/1900
1       StaticData1.2       10/07/2014
1       StaticData1.3       12/12/2015
2       StaticData2.1       01/01/1900
...
n       StaticDataN.1       01/01/1900

当然,所有完整性参考都已消失。当然,由于我不能在ID中添加UNIQUE约束,我无法保留外键。

我在网上搜索了一个解决方案(限制性较少的外键),大部分时间解决方案是使用触发器检查BEFORE INSERT | UPDATE | DELETE

但那将是一项非常非常非常重要的工作。

所以我问,我还有其他解决方案吗? 有没有办法告诉Oracle引用另一个表的另一列,即使认为不是UNIQUE? (肯定不会是空的。)

感谢您的建议:)

2 个答案:

答案 0 :(得分:3)

Oracle 中的主键可能有重复项。可以使用非唯一索引构建主键,并通过使用NOVALIDATE创建约束来排除现有值。这是一个很少使用的功能,会让人感到困惑,并不是一个干净的解决方案。但在现实世界中,有时候数据并不干净,没有时间来完善解决方案。

示例架构和数据。

create table staticData
(
    id number not null,
    data varchar2(100),
    constraint staticData_pk primary key (id)
);

create table typicalTable
(
    id number not null,
    staticDataID number,
    constraint typicalTable_pk primary key (id),
    constraint typicalTable_fk foreign key (staticDataID)
        references staticData(id)
);

insert into staticData values (1, 'StaticData1');
insert into staticData values (2, 'StaticData2');

insert into typicalTable values(1, 1);
insert into typicalTable values(2, 1);

删除约束,添加重复数据以及重新启用约束的过程。

--Drop constraints.
alter table typicalTable drop constraint typicalTable_fk;
alter table staticData drop constraint staticData_pk;

--Add semi-duplicate data.
insert into staticData values (1, 'StaticData1.2');

--Use a non-unique index to build a NOVALIDATE primary key.
create index staticData_pk on staticData(id);
alter table staticData add constraint staticData_pk primary key (id) novalidate;
alter table typicalTable add constraint typicalTable_fk foreign key(staticDataID)
    references staticData(id);

答案 1 :(得分:2)

不,目标列必须是唯一的,这是整个想法。但是,您可以将其他版本列从StaticData传播到TypicalTable:

CREATE TABLE StaticData (
   id           NUMBER, 
   version      NUMBER, 
   col1 ... coln, 
   PRIMARY KEY (id,version)
);

CREATE TABLE TypicalTable (
   StaticDataID NUMBER,
   version      NUMBER,
   colx ... coly,
   FOREIGN KEY (StaticDataID, version) REFERENCES StaticData(id, version)
);