我有以下结构:
Block A
Foo 1
Bar 1
Bar 2
Foo 2
Bar 1
Bar 3
Bar 4
Block B
Foo 3
架构目前是这样的:
Block
1/ \1
n/ \n
Foo-n---m-Bar
问题在于可以有Bar's 属于不同Block的Foo的
是否存在既没有冗余又没有冗余的模式 允许不一致?
答案 0 :(得分:5)
是的,有办法。将Block
的主键列包含在关联表中,并使用它来扩展外键约束:
CREATE TABLE Blocks
( BlockID INT
, PRIMARY KEY (BlockID)
) ;
CREATE TABLE Foos
( BlockID INT
, FooID INT
, PRIMARY KEY (FooID)
, FOREIGN KEY (BlockID)
REFERENCES Blocks (BlockID)
, UNIQUE (BlockID, FooID) -- the Unique constraints are needed for
) ;
CREATE TABLE Bars
( BlockID INT
, BarID INT
, PRIMARY KEY (BarID)
, FOREIGN KEY (BlockID)
REFERENCES Blocks (BlockID)
, UNIQUE (BlockID, BarID) -- the composite FKs below
) ;
CREATE TABLE Foo_Bars -- the m:n association tabletable
( BlockID INT
, FooID INT
, BarID INT
, PRIMARY KEY (FooID, BarID)
, FOREIGN KEY (BlockID, FooID) -- composite FK constraints to Foos
REFERENCES Foos (BlockID, FooID)
, FOREIGN KEY (BlockID, BarID) -- and Bars
REFERENCES Bars (BlockID, BarID)
) ;
答案 1 :(得分:2)
除了ypercube said(+1给他,BTW)之外,如果你愿意改变你的密钥结构,你可以用更少的索引开销来做到这一点:
由于FOO_BAR.BLOCK_ID一直引用两个“分支”直到BLOCK,如果FOO和BAR连接,它们也必须连接到相同的 BLOCK。
除非需要额外的索引(在原始问题范围之外),否则此结构可以非常有效clustered。
答案 2 :(得分:1)
如果我理解正确,你会遇到这样的情况:
<强> block_foo_bar 强>
block foo bar
A 1 1
A 1 2
A 2 1
A 2 3
A 0A 4
B 3 0B
这样的表处理n-m,但它不能强制执行1-n关系。
我的建议是创建另外两个表:
<强> block_foo 强>
block(FK) foo(PK)
A 0A
A 1
A 2
B 0B
B 3
和
<强> block_bar 强>
block(FK) bar(PK)
A 0A
A 1
A 2
A 3
A 4
B 0B
通过这种方式,两个新表将强制执行for / bar-block关系的唯一性。 block_foo_bar将允许您处理n-m关系。为了确保你不会在block_foo和block_bar表中不允许的block_foo_bar关系中在block_foo_bar中创建两个约束:
正如您可能已经注意到我创建了0A和0B之类的虚拟ID,我之所以这样做是因为ID nullable永远不是一个好主意,其次是因为这样我可以在ID上强制执行PK。我知道这意味着这意味着在Foo / Bar表中为每个块创建一个虚拟记录而没有Foo / Bar(更多的ETL工作),但这通常会让我头疼。
希望我的解释对你有意义。