【问题标题】:Oracle Partial Foreign Key that is not unique不唯一的 Oracle 部分外键
【发布时间】:2014-08-31 17:30:24
【问题描述】:

你好互联网的古人!

今天我在使用 Oracle 外部复合键时遇到了一些问题。我有一个有点大的应用程序(你知道,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 约束,所以我不能保留外键。

我已经在网上搜索了一个解决方案(限制较少的外键),大多数时候解决方案是在插入|更新|删除之前使用触发器检查

但这将是一项非常、非常、非常大的工作。

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

感谢您的建议:)

【问题讨论】:

    标签: oracle oracle11g foreign-keys triggers


    【解决方案1】:

    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);
    

    【讨论】:

    • 从未听说过 NOVALIDATE。明天我将对此进行测试,如果可行,将其标记为正确,谢谢!
    【解决方案2】:

    不,目标列必须是唯一的,这就是整个想法。但是,您可以将额外的版本列从 StaticData 传播到典型表:

    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)
    );
    

    【讨论】:

    • +1 这是正确的做法。我的回答通常是错误的方式,但更有趣。 :)
    • 谢谢,我会这样做,但是大多数表对不同的静态数据(更像是五个或六个)有多个 FK,并且向每个典型表添加 4 或 5 个以上的列来添加版本不在我们的脑海中。无论如何,感谢您的正确答案! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多