【问题标题】:How add an optional many to many relationship to another many to many relation table?如何将可选的多对多关系添加到另一个多对多关系表?
【发布时间】:2021-01-19 05:42:23
【问题描述】:

我定义了以下表格:

- Group
  - GroupID (pk - int)
  - ...

- Item
  - ItemID (pk - int)
  - ...

- Groups_Items
  - GroupID (pk - int)
  - ItemID (pk - int)

GroupID 上有一个 FK 链接到 Group 表,ItemID 上有一个 FK 链接到 Item 表。

我需要向 Groups_Items 表添加一个可选关系,即 RuleSetId

- Groups_Items
  - GroupId (pk - int)
  - ItemId (pk - int)
  - RuleSetId (int - nullable)

规则集表定义如下:

- RuleSet
  - RuleSetId (int)
  - RuleId (int)

规则表定义如下:

- Rule
  - RuleId (int)
  - ...

当我尝试使用 RuleSet 表中的 RuleSetId 将 FK 添加到 Groups_Items 表中的 RuleSetId 时,它给了我一个错误,告诉我我不允许。

每个项目必须与一个组相关联,一个组可以有多个项目,但我想提供一个选项,允许一个或多个规则通过规则集与一个项目相关联。请注意,我不想将规则集直接关联到项目本身,而是关联到与组关联的项目,因为项目可能相同但关联到不同的组,并且可能会应用不同的规则集,具体取决于项目的组属于。

我希望这是有道理的。

我正在努力让它工作,所以我一定是设计不正确,但我不确定如何最好地解决这个问题。

更新 - 1

这是我想要实现的图表。请注意,我同时添加了 RuleSet 表,它只包含一个主键,即 RuleSetId

当我尝试在 GroupsItems 表和 RuleSet 表之间添加关系时出现以下错误:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint 
"FK_GroupsItems.ERuleSet". The conflict occurred in database 
"MyDatabase", table "dbo.RuleSet", column 'RuleSetId'.

当我尝试在 RuleSet 表和 RuleSetRules 表之间添加关系时出现以下错误:

Unable to create relationship 'FK_RuleSetsRules.RuleSet'.
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint 
"FK_RuleSetsRules.RuleSet". The conflict occurred in database "MyDatabase", 
table "dbo.RuleSet", column 'RuleSetId.

【问题讨论】:

  • 请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。给出尽可能少的代码,即您显示的代码可以通过您显示的代码扩展为不正常的代码。 (调试基础。)对于包含 DBMS 和 DDL(包括约束和索引)的 SQL,并以表格式作为代码输入。 How to Ask 暂停总体目标的工作,将代码砍到第一个表达式,没有给出你所期望的内容,说出你所期望的内容和原因。
  • use text, not images/links, for text--including tables & ERDs。仅将图像用于无法表达为文本或增强文本的内容。在图片中包含图例/键和说明。
  • @philipx - 为了清楚起见,由于我使用 SQL Server 图表来生成我的关系,因此没有代码可以提供。我列出了带有相关键和外键的表,并尽我所能解释了问题所在。 @Seanb 清楚地理解了我的问题并返回了一个可行的建议和代码,但我已经添加了我想要实现的图表以及发生的具体错误。无论如何,感谢您花时间解释。
  • ERD的内容可以以文本形式给出,该文本称为DDL,也是实现代码的一部分。我的 cmets 并非来自不了解您的问题,而是来自站点协议并希望帮助您获得答案。请注意,由于缺乏问题清晰度和信息,答案有一堆 cmets 和编辑。 PS请不要插入编辑/更新,只是让您的帖子成为编辑时最好的演示文稿。

标签: sql-server database-design many-to-many database-normalization


【解决方案1】:

更新:请注意,在此答案中,我更改了您的“规则集”表的含义。在这个答案中,规则集表创建每个规则集(但不是规则)。 RulesetID 是一个 int 和 PK。然后将规则链接到 Ruleset_Rules 中的此规则集。


我相信规则集表也需要有一个被外键引用的主键。我建议 Ruleset 和 Rules 也获得一个链接它们的多对多表(如果你想重用规则)或将 RulesetID 作为规则中的字段。这个例子有多对多:

CREATE TABLE Grp (GroupID int PRIMARY KEY)
CREATE TABLE Item (ItemID int PRIMARY KEY)

CREATE TABLE RuleSet(RulesetID int PRIMARY KEY)
CREATE TABLE Rules(RuleID int PRIMARY KEY)
GO

CREATE TABLE RuleSet_Rules (RulesetID int, RuleID int, PRIMARY KEY (RulesetID, RuleID))
CREATE TABLE Grp_Item (GroupID int, ItemID int, RuleSetID int, PRIMARY KEY (GroupId, ItemId))
GO

ALTER TABLE [dbo].[Grp_Item] ADD CONSTRAINT [FK_Grp_Item_Grp] FOREIGN KEY([GroupID]) REFERENCES [dbo].[Grp] ([GroupID])
GO
ALTER TABLE [dbo].[Grp_Item] ADD CONSTRAINT [FK_Grp_Item_Item] FOREIGN KEY([ItemID]) REFERENCES [dbo].[Item] ([ItemID])
GO
ALTER TABLE [dbo].[Grp_Item] ADD CONSTRAINT [FK_Grp_Item_Ruleset] FOREIGN KEY([RulesetID]) REFERENCES [dbo].[RuleSet] ([RulesetID])
GO

这是一个db<>fiddle,带有设置和示例插入。

更新:下面是来自 cmets 的updated DB<>fiddle。这有更多的 FK,并解释了某些插入故意失败。

请注意,这假定组/项目的每个组合都可以分配有 0 或 1 个规则集。如果您需要拥有多个规则集,则在 Grp_Item 的多对多表中会变得稍微复杂一些。

另外请注意,我没有创建所有 FK - 只是与 Grp_Item 中当前问题相关的那些。

【讨论】:

  • 我正是这样做的,只是发现了你的回复,即引入了一个 RuleSet 表,它只有一个 RuleSetId 但由于某种原因,如果我试图在它和 RuleSet_Rules 之间添加关系,它就会失败。 Groups_Items 表。我会在一秒钟内尝试你的脚本而不是数据库图,看看我的进展如何。
  • 我添加了一个图表,突出了我想要实现的目标。请注意,我已经运行了您的 dbfiddle,但出现了错误。 “消息 547 级别 16 状态 0 第 2 行 INSERT 语句与 FOREIGN KEY 约束“FK_Grp_Item_Ruleset”冲突。冲突发生在数据库“fiddle_86fe7f407ef641139e4a0af2508ff927”、表“dbo.RuleSet”、列“RulesetID”中。消息 3621 级别 0 状态 0 行2 语句已终止。”
  • 抱歉,我没有明确表示。由于没有 Ruleset_ID 99(表明 FK 约束正在发挥作用),该设计会失败。
  • 还是不行。我已经用图表更新了我的问题。这就是你的建议,不是吗?
  • 嗨,肖恩,你不会相信这一点,但你的建议和我所做的改变一直都是对的!我愚蠢地在表中留下了一些测试数据(我的 RuleSet 和 Rule 表中的单行)导致错误发生!如果你问我,这是一个非常糟糕的错误,但请看,下次发生时我会记住这一点!希望它不会:)。再次感谢。
【解决方案2】:

规则集表定义如下:

- RuleSet
  - RuleSetId (int)
  - RuleId (int)

规则表定义如下:

- Rule
  - RuleId (int)
  - ...

当我尝试使用 RuleSet 表中的 RuleSetId 将 FK 添加到 Groups_Items 表中的 RuleSetId,它给了我一个错误 告诉我我不允许。

请注意,我不想将规则集直接关联到项目 本身,但到与组关联的项目,因为项目可能是 相同但关联到不同的组和不同的一组 可能会根据项目所属的组应用规则。

通过将 RuleSetId 添加到 Groups_Items 表中,RuleSet 和 Items 之间存在显式关联,这是您不想要的。目前,RuleSet 表只包含主键和 RuleId,缺少 GroupId。我认为您正在寻找这样的东西:

规则集表定义如下:

- RuleSet
  - RuleSetId (pk - int)
  - GroupID (fk - int)
  - RuleId (fk - int)

规则表定义如下:

- Rule
  - RuleId (pk - int)
  - ...

现在 RuleSet 表包含 GroupId 和 RuleId 之间的关系,因此没有理由将 RuleSetId 添加到 Groups_Items 表中。

【讨论】:

  • 我明白你在说什么,但你的建议不会让 RuleSet 只与 Group 而不是我需要的 Group & Item 相关联。例如,我可以有 2 个组,即 Private & Public 和一个名为“first name”的项目,我想在其上应用 min len,但“first name”需要 5 个字符,而 public 可能需要 7 个字符。我可以有一个名为 Personal 的第三组,它也使用“名字”并且不需要应用任何规则。这有意义吗?
【解决方案3】:

最简单的方法是从头开始。使用 editor 创建 DDL(模式)。

-- Rule RUL exists.
--
rule {RUL}
  PK {RUL}
-- Rule set RST exists.
--
rset {RST}
  PK {RST}
-- Rule RUL is member of rule set RST.
--
rule_rset {RST, RUL}
       PK {RST, RUL}

FK1 {RST} REFERENCES rset {RST}
FK2 {RUL} REFERENCES rule {RUL}
-- Item ITM exists.
--
item {ITM}
  PK {ITM}
-- Group GRP exists.
--
group {GRP}
   PK {GRP}
-- Item ITM is member of group GRP.
--
item_group {GRP, ITM}
        PK {GRP, ITM}

FK1 {ITM} REFERENCES item  {ITM}
FK2 {GRP} REFERENCES group {GRP}
-- Set of rules RST applies to item ITM in group GRP.
--
item_group_rset {GRP, ITM, RST}
             PK {GRP, ITM}

FK1 {GRP, ITM} REFERENCES item_group {GRP, ITM}

FK2 {RST} REFERENCES rset {RST}

注意:

All attributes (columns) NOT NULL

PK = Primary Key
FK = Foreign Key

【讨论】:

    猜你喜欢
    • 2019-11-07
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    相关资源
    最近更新 更多