2011-04-13 75 views
2

好的,我希望我能够清楚我的问题是什么: 我有一个包含5个表格的数据库。我们称他们为A和B,V_1,V_2和V_3。 A和B代表要完成的事情的列表。这些操作在V_i表中进行了描述。现在,A代表某种东西的模板,必须用某种类型的项目来完成。另一方面,B描述了如果由A描述的抽象项目具体实例需要做什么(或已经完成)。因此,在OOP术语中,可以说A代表一个类并且B代表A的实例。只要有东西插入表B中,表A的相关数据就会被复制,因此它可以在不影响A的情况下修改该特定项目。与多个表格中的一个表格进行1对1的关系

好的,这里是实际的问题:我如何建模正常吗?我主要关心的是,V_i中的每条记录都不能与A和B都链接。它必须与A或B都是1:1的关系。另外,V_i和V_j不能链接到A中的相同记录,或者B.我不知道如何正确地做到这一点。目前的结构如下所示:

A和B有一个叫ID的PK。每个V_i也有一个称为ID的PK和两个参考A或B的FK,我们称它们为A_ID和B_ID。现在,当前的实现确保A_ID或B_ID为NULL,但不是两者。但是,我想知道是否有更好的方法来做到这一点。此外,还有问题是多个V_i可能引用A或B中的相同条目。

所以,我希望我的问题很清楚。有没有一种方法可以在不依赖外部代码来强制约束的情况下使用关系数据库对此进行正确建模?感谢您的提前输入。

问候 大卫

+0

我想你会需要查找表。尽管如此,我不确定最佳实现方式,但希望像Quassnoi,OMG_Ponies,gbn,martin,Joe Stefanelli或SQLMenace这样聪明的人能够投入进来! – JNK 2011-04-13 12:05:07

回答

1

第一件事:在设计数​​据库时,你表达不记录表之间的关系。 你用OO的观点来表达你的问题。这种范式不能用于设计表(SQL是一种声明性语言)。

否则,你可以在你的表上添加约束来确保你的谓词。

也许Oracle提供了其他我不知道的可能性。

+0

更多信息www。 asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1545206281987 – 2011-04-13 12:56:09

+0

通常,简单表达不同的问题会导致另一种解决方案。检查你的关系。你能确定你的V-i表吗? – 2011-04-13 13:03:02

2

在关系理论中,一对一关系通常被翻译成物理模型中的单个表格。这个单表将包含来自两个表的行,并且您将使用检查约束来确定行的类型。这是获得可靠的1对1关系的最简单方法。

0

的类模型最常用的方法 - 在RDBS实例关系是 类=表 实例=行

想想看:你插入为每一个新实例的新行;你不插入数据的地方,插入默认值,它给你类的数据;和触发器给你的课堂级别的行为。

或者,给A和B相同的主键,并将B的PK设置为F的A到PK。当B包含一行时,DBMS将检查“父”行是否存在在A.大约需要绘制

+--------+ +--------+ 
|Table A | |Table B | 
+--------+ +--------+ 
|id (PK) |<--|id* (PK)| 
|col1 | |colB1 | 
| ... | | ... | 
+--------+ +--------+ 
0

前言:这是一个不好的设计,正如其他人指出。

假设:

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

强制规定,在任何或B从A的ID的恰好一个是必需的V_i表的(但不是两者)是很容易的。

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存在于V_i表中的一个且仅有一个中。这不能在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;