6

こんにちは、私はこれに少し苦労しており、いくつかのアイデアを使用できます...

私のデータベースに次のテーブルがあるとします。顧客 サプライヤー SalesInvoices PurchaseInvoices 通貨

などなど

「メモ」レコードを任意のタイプのレコードに追加できるようにしたい

ノートテーブルはこれを望んでいます

NoteID        Int (PK)
NoteFK        Int
NoteFKType    Varchar(3)
NoteText      varchar(100)
NoteDate      Datetime

NoteFK は顧客やサプライヤーなどの PK であり、NoteFKType はノートが対象とするレコードのタイプを示します。

NoteFK がすべてのテーブルに存在する必要がなければ、複数のテーブルを参照する FK を追加できないことに気付きました。

では、上記をどのように設計しますか? Note FK は、上記のテーブルのいずれかにある必要があります

乾杯、ダニエル

4

8 に答える 8

3

この外部キー制約についてデータベースに教えることができないという制限を受け入れる必要があります。したがって、整合性チェック (およびカスケード削除) なしで行う必要があります。

あなたのデザインは素晴らしいです。追加のテーブルに簡単に拡張でき、エンティティごとに複数のメモを持つことができ、ターゲット テーブルはメモ機能を認識する必要さえありません。

エンティティ テーブルごとに個別のメモ テーブルを使用するよりもこの設計の利点は、"最新のメモ" や "特定のユーザーによって作成されたすべてのメモ" など、すべてのメモに対して簡単にクエリを実行できることです。

そのテーブルが大きくなりすぎるという議論については、たとえば 5 つのテーブルに分割すると、テーブルのサイズは約 5 分の 1 に縮小されますが、これはインデックス ベースのアクセスには何の違いもありません。データベースは、(適切にインデックスが作成されている限り) 大きなテーブルを処理するように構築されています。

于 2009-07-24T11:43:15.590 に答える
2

メモが他のテーブルの既存のエンティティを参照しているかどうかをデータベースシステムがチェックしないという事実を受け入れることができれば、あなたの設計は問題ないと思います。これは、重複を必要とせず、より多くのテーブルに拡張できる、私が考えることができる唯一の設計です。

設計した方法では、メモを取りたい別のエンティティ タイプを追加するときに、モデルを変更する必要はありません。また、既存のモデルや追加のテーブルに追加の列を含める必要はありません。

データの整合性を確保するために、一連のトリガーまたはノート テーブルをときどき消去するソフトウェア ソリューションを作成できます。

于 2009-07-24T11:40:53.800 に答える
1

私はマイケル・マクロスキーにある程度同意します。

私の頭の中にある質問は、複数のノートテーブルを持つことの技術的コストはどれくらいかということです。

私の考えでは、同じ機能を1つのテーブルに統合することが望ましいです。また、レポート作成やその他のさらなる開発が簡単になります。テーブルのリストを小さくして管理しやすくすることは言うまでもありません。

これはバランスをとる行為であり、このようなことを行うことのメリットとコストの両方を事前に決定する必要があります。私の個人的な好みは、データベースの参照整合性です。私の意見では、整合性のアプリケーション管理はビジネスロジックに限定されるべきです。データベースは、データが常に一貫性があり有効であることを保証する必要があります...


実際にあなたの質問に答えるために...

私が使用するオプションは、ユーザー定義関数を使用して値をチェックするチェック制約です。これはM$SQLServerで機能します...

CREATE TABLE Test_Table_1 (id INT IDENTITY(1,1), val INT)
GO
CREATE TABLE Test_Table_2 (id INT IDENTITY(1,1), val INT)
GO
CREATE TABLE Test_Table_3 (fk_id INT, table_name VARCHAR(64))
GO

CREATE FUNCTION id_exists (@id INT, @table_name VARCHAR(64))
RETURNS INT
AS
BEGIN
    IF (@table_name = 'Test_Table_1')
        IF EXISTS(SELECT * FROM Test_Table_1 WHERE id = @id)
            RETURN 1
    ELSE
    IF (@table_name = 'Test_Table_2')
        IF EXISTS(SELECT * FROM Test_Table_2 WHERE id = @id)
            RETURN 1

    RETURN 0
END
GO

ALTER TABLE Test_Table_3 WITH CHECK ADD CONSTRAINT
    CK_Test_Table_3 CHECK ((dbo.id_exists(fk_id,table_name)=(1)))
GO
ALTER TABLE [dbo].[Test_Table_3] CHECK CONSTRAINT [CK_Test_Table_3]
GO

INSERT INTO Test_Table_1 SELECT 1
GO
INSERT INTO Test_Table_1 SELECT 2
GO
INSERT INTO Test_Table_1 SELECT 3
GO
INSERT INTO Test_Table_2 SELECT 1
GO
INSERT INTO Test_Table_2 SELECT 2
GO
INSERT INTO Test_Table_3 SELECT 3, 'Test_Table_1'
GO
INSERT INTO Test_Table_3 SELECT 3, 'Test_Table_2'
GO

その例では、最後の挿入ステートメントは失敗します。

于 2009-07-24T13:04:28.073 に答える
1

FK参照整合性を取得できますが、notesテーブルに1つの列があります。

create table Notes (
    id int PRIMARY KEY,
    note varchar (whatever),
    customer_id int NULL REFERENCES Customer (id),
    product_id int NULL REFERENCES Product (id)
)

次に、列が1つだけ設定されていることを確認するための制約が必要になります。

あるいはそうではないかもしれませんがメモを顧客と製品の両方に関連付けることができるようにしたい場合があります。君による。

この設計では、別の参照テーブルを追加する場合は、Notesに新しい列を追加する必要があります。

于 2009-07-24T13:07:39.353 に答える
1

私はあなたが提案することをする前によく考えます。短期的にはシンプルでエレガントに見えるかもしれませんが、データの整合性とパフォーマンスに本当に関心がある場合は、親テーブルごとに個別のノートテーブルを用意することをお勧めします。何年にもわたって、私は他の回答(トリガー、GUIDなど)にある解決策を使用してこの問題に取り組みました。追加された複雑さとパフォーマンスの低下は、それだけの価値がないという結論に達しました。適切な外部キー制約を使用して、親テーブルごとに個別のノートテーブルを設定することにより、ルックアップと結合が簡単かつ高速になります。関連するアイテムを1つのテーブルに結合すると、結合構文が醜くなり、メモテーブルが巨大で遅くなります。

于 2009-07-24T12:24:54.177 に答える
0

Customers、Suppliers などのテーブルに GUID フィールドを追加できます。次に、Notes テーブルで、その GUID を参照するように外部キーを変更します。

これは、データの整合性には役立ちません。ただし、任意の数のテーブルに対して M 対 N の関係を簡単に作成できるため、Notes テーブルで NoteFKType 列を定義する必要がなくなります。

于 2009-07-24T11:37:44.650 に答える
0

トリガーを使用して「マルチ」外部キーを簡単に実装できます。トリガーは非常に柔軟なメカニズムを提供し、必要な整合性チェックを実行できます。

于 2009-07-24T12:01:23.667 に答える
-2

逆に、他のテーブル (Customer、Supplier など) に NotesID への外部キーを持たないでください。このようにして、1 対 1 のマッピングが行われます。

于 2009-07-24T11:37:18.347 に答える