如何用最喜欢的强制约束物理地表示父子关系?

时间:2014-02-04 11:05:03

标签: sql sql-server database-design sql-server-2012

我有一对必须合理频繁出现的逻辑实体关系。

考虑两个实体ParentChild。不可思议的是,每个Parent至少有一个或多个Children

到目前为止显而易见。

此外,每个Parent只有一个收藏 Child

我有一些限制或要求可以告知最佳解决方案,

  • ChildParent都有一个主键,即一个Indentity列。

  • 解决方案必须尽可能强化诚信。我不想让没有孩子的父母,没有最爱或孤儿的父母。

  • 我想简单快捷地访问父母最喜欢的孩子。

  • 我希望所有的孩子,包括最爱的孩子都在同一张桌子上,所以我可以在没有工会或加入的情况下搜索他们。

  • 我需要能够在表格中插入数据。


这是我从fiddle here

开始的地方
CREATE TABLE [Parent]
(
    [Id] INT NOT NULL IDENTITY,
    [FavouriteChildId] INT NOT NULL,
    [Other] NVARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_Parent] PRIMARY KEY ([Id])
);

CREATE TABLE [Child]
(
    [Id] INT NOT NULL IDENTITY,
    [ParentId] INT NOT NULL,
    [Other] NVARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_Child] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Child_Parent]
        FOREIGN KEY ([ParentId]) REFERENCES [Parent]([Id])
);

ALTER TABLE [Parent]
    ADD CONSTRAINT [FK_Parent_FavouriteChild]
        FOREIGN KEY ([FavouriteChildId]) REFERENCES [Child]([Id]);

除了我无法插入数据外,这满足了我的所有要求。

1 个答案:

答案 0 :(得分:1)

这就是我要做的。对你的约束略微放松,但希望足够接近:

CREATE TABLE [Parent]
(
    [Id] INT NOT NULL IDENTITY,
    [Other] NVARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_Parent] PRIMARY KEY ([Id])
);

CREATE TABLE [Child]
(
    [Id] INT NOT NULL IDENTITY,
    [ParentId] INT NOT NULL,
    IsFavourite bit not null,
    FavouriteMarker as CASE WHEN IsFavourite = 1 THEN 1 ELSE -Id END persisted,
    FavouriteRef as CASE WHEN IsFavourite = 0 THEN 1 END persisted,
    [Other] NVARCHAR(MAX) NOT NULL,
    CONSTRAINT [PK_Child] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Child_Parent]
        FOREIGN KEY ([ParentId]) REFERENCES [Parent]([Id]),
    CONSTRAINT UQ_Child_Favourite UNIQUE (ParentID,FavouriteMarker),
    CONSTRAINT FK_Child_FavouriteReference FOREIGN KEY (ParentID,FavouriteRef)
        references Child (ParentID,FavouriteMarker)
);

和一些陈述来运用这些表格:

insert into Parent (Other) values ('ABC'); --We'll assume this gets assigned ID 1

insert into Child (ParentId,IsFavourite,Other) values (1,0,'def') --Fails - no favourite child yet
insert into Child (ParentId,IsFavourite,Other) values (1,1,'ghi') --Succeeds
insert into Child (ParentId,IsFavourite,Other) values (1,1,'jkl') --Fails - no second favourite
insert into Child (ParentId,IsFavourite,Other) values (1,0,'mno') --Succeeds
insert into Child (ParentId,IsFavourite,Other) values (1,0,'pqr') --Succeeds
update Child set IsFavourite =
        CASE WHEN Other = 'mno' THEN 1 ELSE 0 END
where Other in ('ghi','mno') --Succeeds, favourite changed
delete from Parent where Id = 1 --Fails - no orphans

所以它确实允许无子女的父母存在,并且没有最喜欢的孩子的唯一父母正是那些没有孩子的父母。为特定父级添加子级的第一个INSERT可能是多行插入,但必须包含一个(并且恰好一个)标记为收藏的子级。此后,可以更改收藏夹。