与多个表中的一个精确一对一的关系

| 好的,希望我能弄清楚我的问题是什么: 我有一个包含5个表的数据库。我们称它们为A和B,V_1,V_2和V_3。 A和B代表要完成的事情的列表。这些动作在V_i表中描述。现在,A代表某种必须使用某种类型的物料完成的物料模板。另一方面,B描述了如果由A描述的抽象项必须用一个具体实例完成(或已经完成)的事情。因此,在OOP术语中,人们可能会说A代表一个类,而B代表A的一个实例。每当将什么插入表B中时,都会复制表A中的相关数据,以便可以为该特定项目修改它而不影响A。 好的,这是实际的问题:如何正确建模?我主要担心的是,V_i中的每个记录都不能同时链接到A和B。它必须与A或B保持一对一的关系。而且,V_i和V_j不能链接到A或B中的同一记录。 B.我不知道如何正确执行此操作。当前结构如下: A和B具有称为ID的PK。每个V_i还具有一个称为ID的PK和两个引用A或B的FK,我们将它们称为A_ID和B_ID。现在,当前实现可确保A_ID或B_ID为NULL,但不能同时为NULL。但是,我想知道是否有更好的方法可以做到这一点。此外,存在多个V_i可以引用A或B中的同一条目的问题。 所以,我希望我的问题很清楚。有没有一种方法可以使用关系数据库正确地对此建模,而无需依赖外部代码来强制执行约束?感谢您的预先输入。 最好的祝福 大卫     
已邀请:
在关系理论中,通常将一对一关系转换为物理模型中的单个表。该单个表将包含两个表中的行,并且您将使用检查约束来确定行的类型。到目前为止,这是获取可靠的一对一关系的最简单方法。     
第一件事:设计数据库时,您表示的是记录之间的关系,而不是表。 您是用面向对象的观点表达您的问题。此范例不能用于设计表(SQL是一种声明性语言)。 否则,您可以在表上添加约束以确保您的谓词。 也许Oracle提供了我不知道的其他可能性。     
在rdbs中建模类-实例关系的最常见方法是 类=表 实例=行 考虑一下:为每个新实例插入新行;在不插入数据的地方,插入默认值,从而为您提供类数据;触发器会为您提供班级的行为。 或者,给A和B相同的主键,并将B的PK设置为A的PK的FK。当B中包含一行时,DBMS将检查A中是否存在“父”行。可能需要绘图
+--------+   +--------+
|Table A |   |Table B |
+--------+   +--------+
|id (PK) |<--|id* (PK)|
|col1    |   |colB1   |
| ...    |   | ...    |
+--------+   +--------+
    
前言:正如其他人指出的那样,这是一个糟糕的设计。 假设:
create table a (a_id number primary key); 

create table b (b_id number primary key); 

create table v1 
(v1_id number primary key, a_id number references a, b_id number references b);

create table v2
(v2_id number primary key, a_id number references a, b_id number references b);

create table v3
(v3_id number primary key, a_id number references a, b_id number references b);
在任何一个“ 2”表中强制要求仅提供A或B中的一个ID(但不是两个都一样)非常容易。
alter table V1
  add constraint v1_check check
  (    (a_id is null and b_id is not null)
    or (a_id is not null and b_id is null)
  );
如果要扩展该约束,以使A或B中的ID恰好存在,并且该值仅存在于一行中,则仅存在一行:
create unique index v1_check_unique on v1  ( coalesce (a_id, b_id) );
困难的部分是确保A和B中的id存在于一个“ѭ2”表中,并且只有一个。这不能在DML时完成,但是可以在提交时强制执行。
create materialized view log on v1 with rowid;
create materialized view log on v2 with rowid;
create materialized view log on v3 with rowid;
CREATE MATERIALIZED VIEW CROSS_TABLE
REFRESH FAST ON COMMIT
AS
  SELECT V1_ID AS V_ID, \'V1\' AS TABLE_NAME, ROWID AS ROW_ID, 
         COALESCE (A_ID, B_ID) AS OTHER_ID FROM V1
  UNION ALL
  SELECT V2_ID AS V_ID, \'V2\' AS TABLE_NAME, ROWID AS ROW_ID, 
         COALESCE (A_ID, B_ID) AS OTHER_ID FROM V2
  UNION ALL
  SELECT V3_ID AS V_ID, \'V3\' AS TABLE_NAME, ROWID AS ROW_ID, 
         COALESCE (A_ID, B_ID) AS OTHER_ID FROM V3
/

ALTER TABLE CROSS_TABLE ADD CONSTRAINT CROSS_TABLE_UNIQUE UNIQUE (OTHER_ID);
这似乎有效-但不如您希望的那样出色。 Oracle无法在语句时在表之间强制执行这种唯一性,因为不允许会话A考虑其他会话可能进行的任何其他更改。它只能在提交时强制执行该唯一性。 以下测试用例在针对空表运行时失败-并回滚整个事务,因为它无法推断出导致失败的原因。买者自负。
INSERT INTO A VALUES (1);
INSERT INTO B VALUES (1);
INSERT INTO V1 (V1_ID, A_ID, B_ID) VALUES (1, 1, NULL);
INSERT INTO V2 (V2_ID, A_ID, B_ID) VALUES (1, 1, NULL);
COMMIT;
    

要回复问题请先登录注册