3

ノートテーブルがあるとしましょう。メモは、特定のアカウント、注文明細、または注文に関するものにすることができます。

  • アカウントに関する注記は、特定の注文ラインまたは注文には適用されません。
  • 注文明細に関する注記は、親注文と注文に添付されているアカウントにも適用されます。
  • 注文に関する注記は、添付のアカウントにも適用されますが、注文ラインには適用されません。

NOTES表

[Id]          [int] IDENTITY(1,1) NOT NULL
[NoteTypeId]  [smallint] NOT NULL
[AccountId]   [int] NULL
[OrderId]     [int] NULL
[OrderLineId] [int] NULL,
[Note]        [varchar](300) NOT NULL

クライアントを表示すると、何らかの形で関連しているすべてのメモを表示できるという考え方です。最初に、上記のそれぞれについてメモテーブルを作成し、ビューでそれらを結合しました。ここでの問題は、レコードの編集/削除にあります。メモは、特定のアイテムで、またはアカウントまたは注文の一般的なメモビューで編集/削除できます。この方法はそれをより困難にしました。

次に、単一テーブル継承パターンに切り替えました。私のメモテーブルには、AccountId、OrderId、およびOrde​​rLineIdのnull許容値があります。また、レコードを明示的に識別するためにNoteTypeIdを追加しました。更新/削除シナリオの管理がはるかに簡単です。

このアプローチにはまだいくつかの問題と質問があります。

  • 整合性-複雑な制約はSQLやコードで設定できますが、ほとんどのDBAはSTIアプローチを望んでいません。
  • 多数のnullの概念が議論されています(ただし、SQL 2008のパフォーマンスはnull値の格納に基づいて改善されたと思います)
  • RDBMSのテーブルは、コードでオブジェクトを表す必要はありません。テーブルの正規化は、テーブルが一意のオブジェクトである必要があるとは言いません。私は前の2つの文が真実であると信じています、あなたは何と言いますか?

ここでいくつか議論しました。 データベース内のnull許容列の乱用は「コードの臭い」ですか?私はイアンに同意すると言わざるを得ませんが、反対の見方もいくつか望んでいます。

4

3 に答える 3

2

複雑な制約は SQL やコードで設定できますが、ほとんどの DBA は STI アプローチを好まないでしょう。

メモがエンティティ (アカウント、注文、オーダーライン) の 1 つだけを参照するというビジネス ルールを実装するには、追加のロジック (CHECK 制約またはトリガー) が必要なためです。

各エンティティとノート テーブルの間に多対多テーブルを実装する方がスケーラブルです。

  • ALTER TABLE ステートメントでさらに別の null 許容外部キーを追加する必要はありません (列の制限がありますが、ほとんどがそれに到達する可能性は低いです)。
  • 1 つのメモ レコードを複数のエンティティに関連付けることができます
  • 新しいエンティティと多対多テーブルが追加された場合、既存のレコードへの影響はありません
于 2010-07-29T19:30:55.057 に答える
0

あなたの場合、STIは問題なく機能するようです。要件を正しく読んだ場合、エンティティの継承はチェーンになります。

注<-AccountNote(AccountId)<-AccountAndOrderNote(OrderId)<-AccountAndOrderAndOrderLineNote(OrderLineId)

誠実さ:確かに問題ではありませんか?AccountId、OrderId、およびOrde​​rLineIdのそれぞれをそれぞれのテーブルにFKする(またはNULLにする)ことができます。一方、AccountId、OrderId、およびOrde​​rLineIdを削除した場合(ところではお勧めしません!)、代わりにObjectIdとNoteTypeIdだけを削除します。 、その後、RIを追加できず、Joinタイプの場合は非常に厄介なCASEWHENになります。

パフォーマンス:AccountIdは常に存在する必要があると言っているので、null以外の可能性があると思います。また、OrderLineはOrderなしでは存在できないため、(AccountId、OrderId)または(AccountId、OrderId、OrderLineId)のインデックスは理にかなっているようです(選択可能性と注文あたりの平均#OrderLinesの狭さのトレードオフに応じて)

しかし、OMG Poniesは、これを新しいノートタイプに拡張するための厄介なALTER TABLEについて正しいので、新しいノートがアカウントから派生していない場合、インデックス作成は頭痛の種になります。

HTH

于 2010-07-29T21:08:19.057 に答える
0

最初に、上記のそれぞれについて個別のメモテーブルを[作成]し、それらをビューで結合しました。

これは、タイプに関係なく各メモが一意の ID を取得する、NULL 可能な列のない複数テーブル構造の使用を検討したかどうか疑問に思います。を使用せずに、クエリで「単一テーブルの継承」(または同様のもの) でデータを提示できますUNION

以下は、推奨される構造です。VARCHAR に変更して、さまざまな型をより明確にし、読みやすくしました (とにかく値をNoteTypeId列挙しませんでした)。INTEGER

CREATE TABLE Notes
(
 Id INTEGER IDENTITY(1,1) NOT NULL UNIQUE, 
 NoteType VARCHAR(11) NOT NULL
    CHECK (NoteType IN ('Account', 'Order', 'Order line')), 
 Note VARCHAR(300) NOT NULL, 
 UNIQUE (Id, NoteType)
);

CREATE TABLE AccountNotes
(
 Id INTEGER NOT NULL UNIQUE, 
 NoteType VARCHAR(11) 
    DEFAULT 'Account' 
    NOT NULL
    CHECK (NoteType = 'account'),
 FOREIGN KEY (Id, NoteType)
    REFERENCES Notes (Id, NoteType)
       ON DELETE CASCADE, 
 AccountId INTEGER NOT NULL
    REFERENCES Accounts (AccountId)
);

CREATE TABLE OrderNotes
(
 Id INTEGER NOT NULL UNIQUE, 
 NoteType VARCHAR(11) 
    DEFAULT 'Order'
    NOT NULL
    CHECK (NoteType = 'Order'),
 FOREIGN KEY (Id, NoteType)
    REFERENCES Notes (Id, NoteType)
       ON DELETE CASCADE, 
 OrderId INTEGER NOT NULL
    REFERENCES Orders (OrderId)
);

CREATE TABLE OrderLineNotes
(
 Id INTEGER NOT NULL UNIQUE, 
 NoteType VARCHAR(11) 
    DEFAULT 'Order line'
    NOT NULL
    CHECK (NoteType = 'Order line'),
 FOREIGN KEY (Id, NoteType)
    REFERENCES Notes (Id, NoteType)
       ON DELETE CASCADE, 
 OrderLineId INTEGER NOT NULL
    REFERENCES OrderLines (OrderLineId)
);

「単一テーブル継承」構造でデータを表示するには (つまり、すべてJOINがあり、 がないUNION):

SELECT N1.Id, N1.NoteType, N1.Note, 
       AN1.AccountId, 
       ON1.OrderId, 
       OLN1.OrderLineId
  FROM Notes AS N1
       LEFT OUTER JOIN AccountNotes AS AN1
          ON N1.Id = AN1.Id
       LEFT OUTER JOIN OrderNotes AS ON1
          ON N1.Id = ON1.Id
       LEFT OUTER JOIN OrderLineNotes AS OLN1
          ON N1.Id = OLN1.Id;

上記の構造には完全なデータ整合性制約があることを考慮してください。「単一テーブルの継承」構造を使用して同じことを行うには、CHECKnull 許容列の多くの条件を持つ、さらに多くの制約が必要になります。

CHECK (
       (
        AccountId IS NOT NULL
        AND OrderId IS NULL
        AND OrderLineId IS NULL
       )
       OR
       (
        AccountId IS NULL
        AND OrderId IS NOT NULL
        AND OrderLineId IS NULL
       )
       OR
       (
        AccountId IS NULL
        AND OrderId IS NULL
        AND OrderLineId IS NOT NULL
       )
      );

CHECK (
       (
        NoteType = 'Account'
        AND AccountId IS NOT NULL
       )
       OR
       (
        NoteType = 'Order'
        AND OrderId IS NOT NULL
       )
       OR 
       (
        NoteType = 'Order line'
        AND OrdereLineId IS NOT NULL
       )
      );

etc etc

「単一テーブルの継承」を使用するほとんどのアプリケーション開発者は、これらのデータ整合性制約を作成することを思いついたとしても、わざわざ作成することはないと思います (失礼に聞こえるという意味ではありません。 「フロントエンド」よりも「バックエンド」に気を配ってください :)

于 2010-07-30T09:52:17.067 に答える