私が考えることができる他の唯一の方法は、Id と TypeId の両方を持つベース メッセージ テーブルを持つことです。次に、サブテーブル (QuoteMessage および JobMessage) は、MessageId と TypeId の両方でベース テーブルを参照しますが、適切な MessageTypeId のみを適用するためにそれらに CHECK CONSTRAINTS も設定します。
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 テーブルと比較して、これによって何が得られますか? 単一のテーブルからすべてのメッセージを読み取ることができるように、メッセージを第一級市民に昇格させます。代わりに、Message から関連する Quote または Job へのクエリ パスは、もう 1 つ離れています。それが良いトレードオフであるかどうかは、アプリのフローに依存します。
DRYに違反する2つの同一のテーブルについては、私はそれに夢中になりません。DB 設計では、DRY よりも正規化が重要です。モデリングしている 2 つのものが同じ属性 (列) を持っているが、実際には異なるもの (テーブル) である場合、同様のスキーマを持つ複数のテーブルを持つことは合理的です。さまざまなものを一緒にいじる逆よりもはるかに優れています。