【问题标题】:SQL2005: Linking a table to multiple tables and retaining Ref Integrity?SQL2005:将一个表链接到多个表并保持参考完整性?
【发布时间】:2010-09-06 09:05:39
【问题描述】:

这是我的数据库的简化:

表:属性
字段:ID、地址

表:报价
字段:ID、PropertyID、BespokeQuoteFields...

表:工作
字段:ID、PropertyID、BespokeJobFields...

然后我们有其他表分别与 QuoteJob 表相关。

我现在需要添加一个 Message 表,用户可以在其中记录客户留下的有关 Jobs 和 Quotes 的电话消息。

我可以创建两个相同的表(QuoteMessageJobMessage),但这违反了 DRY 原则并且看起来很乱。

我可以创建一个 Message 表:

表:消息
字段:ID、RelationID、RelationType、OtherFields...

但这阻止了我使用约束来强制我的参照完整性。我也可以预见它会在以后使用 Linq to SQL 给开发端带来问题。

这个问题有没有优雅的解决方案,还是我最终不得不一起破解一些东西?

烧伤

【问题讨论】:

    标签: database sql-server-2005 referential-integrity


    【解决方案1】:

    创建一个 Message 表,其中包含唯一的 MessageId 和您需要为消息存储的各种属性。

    Table: Message
    Fields: Id, TimeReceived, MessageDetails, WhateverElse...
    

    创建两个链接表 - QuoteMessage 和 JobMessage。这些将仅包含两个字段,即报价/作业和消息的外键。

    Table: QuoteMessage
    Fields: QuoteId, MessageId
    
    Table: JobMessage
    Fields: JobId, MessageId
    

    通过这种方式,您只在一个地方定义了 Message 的数据属性(使其易于扩展和查询所有消息),但您还具有将 Quotes 和 Jobs 链接到任意数量的消息的引用完整性.事实上,Quote 和 Job 都可以链接到 same 消息(我不确定这是否适合您的业务模型,但至少数据模型为您提供了选项)。 p>

    【讨论】:

      【解决方案2】:

      关于我能想到的唯一其他方法是拥有一个基本消息表,其中包含一个 Id 和一个 TypeId。然后,您的子表(QuoteMessage 和 JobMessage)在 MessageId 和 TypeId 上引用基表 - 但它们上也有 CHECK CONSTRAINTS 以仅强制执行适当的 MessageTypeId。

      Table: Message
      Fields: Id, MessageTypeId, Text, ...
      Primary Key: Id, MessageTypeId
      Unique: Id
      
      Table: MessageType
      Fields: Id, Name
      Values: 1, "Quote" : 2, "Job"
      
      Table: QuoteMessage
      Fields: Id, MessageId, MessageTypeId, QuoteId
      Constraints: MessageTypeId = 1
      References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
                  QuoteId = Quote.QuoteId
      
      Table: JobMessage
      Fields: Id, MessageId, MessageTypeId, JobId
      Constraints: MessageTypeId = 2
      References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
                  JobId = Job.QuoteId
      

      与仅 JobMesssage 和 QuoteMessage 表相比,这能为您带来什么?它将消息提升为一等公民,以便您可以从单个表中读取所有消息。作为交换,您从消息到相关报价或工作的查询路径是另外 1 个连接。这在某种程度上取决于您的应用流程,这是否是一个好的权衡。

      至于 2 个相同的表违反 DRY - 我不会挂断电话的。在 DB 设计中,它与 DRY 无关,而更多地与规范化有关。如果您正在建模的 2 个事物具有相同的属性(列),但实际上是不同的事物(表) - 那么拥有多个具有相似架构的表是合理的。比把不同的东西混在一起要好得多。

      【讨论】:

        【解决方案3】:

        @烧伤

        Ian 的回答 (+1) 是正确的[见注释]。使用多对多表QUOTEMESSAGEQUOTE 连接到MESSAGE 是最正确的模型,但会留下孤立的MESSAGE 记录。

        这是可以使用触发器的那些罕见情况之一。但是,需要注意确保单个MESSAGE 记录不能同时与QUOTEJOB 关联。

        create trigger quotemessage_trg
        on quotemessage
        for delete
        as
        begin
        
        delete 
        from [message] 
        where [message].[msg_id] in 
            (select [msg_id] from Deleted);
        
        end
        

        Ian 请注意,我认为JobMessage 的表定义中有错字,其中的列应为JobId, MessageId (?)。我会编辑你的报价,但我可能需要几年时间才能获得那种级别的声誉!

        【讨论】:

          【解决方案4】:

          为什么不在消息表中同时包含 QuoteId 和 JobId 字段?或者消息必须与报价或工作有关,而不是两者兼而有之?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-27
            • 2010-09-26
            • 1970-01-01
            • 2012-08-13
            • 2013-05-21
            • 1970-01-01
            相关资源
            最近更新 更多