1

組織内に支店用のテーブルがあるとします。それらのいくつかは「メイン」ブランチであり、その他はメイン ブランチにロールアップされるサテライト オフィスです。システム内のいくつかの事柄にのみ影響するこの違いを除けば、ブランチはすべてピアであり、同じ属性 (アドレスなど) を持っています。これをモデル化する 1 つの方法は、次のような表です。

CREATE TABLE Branch (
    branch_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    branch_name VARCHAR(80) NOT NULL,
    street VARCHAR(80) NULL,
    city VARCHAR(30) NULL,
    state CHAR(2) NULL,
    zip CHAR(5) NULL,
    is_satellite_office BIT NOT NULL DEFAULT(0),
    satellite_to_branch_id INT NULL REFERENCES Branch(branch_id)
)

Where is_satellite_office= 1 このレコードが別のブランチsatellite_to_branch_idのサテライトであり、サテライトであるブランチがある場合はそのブランチを参照します。

これらの 2 つの列が特定のレコードで一致するように、テーブルに制約を設定するのは簡単です。

CONSTRAINT [CK_Branch] CHECK 
  (
    (is_satellite_office = 0 AND satellite_to_branch_id IS NULL) 
    OR (is_satellite_office = 1 AND satellite_to_branch_id IS NOT NULL)
  )

しかし、私が本当に欲しいのは、この再帰が1レベルの深さだけになることを保証する方法です...つまり、親としてブランチを指す場合、それは親自体を持ってはならず、その値is_satellite_officeは0. 別の言い方をすれば、私は完全に再帰的なツリー構造を望んでいません。単一の親子関係に制限したいだけです。それが私がコードを書く方法であり、完全にがらくたのように実行されないデータベースでそれを強制する方法があれば、私はそうしたいと思います。

何か案は?私は MSSQL 2005 に取り組んでいますが、一般的な (ベンダー固有ではない) ソリューションが優先されます。他に方法がない場合を除き、トリガーを適用する必要はありません。

編集: 明確にするためsatellite_to_branch_idに、同じブランチ テーブル内の別のレコードへの再帰的なポインターです。is_satellite_office BITを削除して、同じ情報を提供することに頼ることができることは知っていIsNull(satellite_to_branch_id)ますが、明示的にする方が少し明確であり、さらに、それは質問の要点ではありません。再帰の深さが 1 を超えるのを防ぐための純粋な SQL 制約の方法を本当に探しています。

4

4 に答える 4

1

チェック制約を UDF の戻り値にバインドできます。関連する列を入力パラメーターとして受け取る UDF を作成し、UDF の選択を使用して目的の状態を確認します。

于 2009-01-08T17:33:01.453 に答える
1

制約でストアド プロシージャを参照することはできませんか? PostgreSQL ではできるので、2005 年にこれが許可されなかったとしたら驚きです。

于 2009-01-08T17:01:26.680 に答える
1

データ定義レベルで強制するのが難しい、ビジネス上の制約のように思えます。リレーショナル代数が自己参照の深さの制限を決定するためのサポートを持っているとは思えません。

于 2009-01-08T16:35:27.467 に答える
0

このわずかに異なる構造はどうですか?

CREATE TABLE Branch (
    branch_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
    branch_name VARCHAR(80) NOT NULL,
    street VARCHAR(80) NULL,
    city VARCHAR(30) NULL,
    state CHAR(2) NULL,
    zip CHAR(5) NULL,
    parent_id int NULL
)

PARENT_ID は、同じテーブル内の別のレコードの BRANCH_ID を指すだけです。null の場合、親がないことがわかります。

次に、再帰の 1 つのレベルを取得するには、次のように、テーブルをそれ自体に 1 回結合するだけです。

SELECT
  PARENT.BRANCH_NAME AS PARENT_BRANCH
 ,CHILD.BRANCH_NAME AS CHILD_BRANCH
FROM
  BRANCH PARENT
 ,BRANCH CHILD
WHERE CHILD.PARENT_ID PARENT.BRANCH_ID

ツリーに 1 レベルの深さを強制する場合は、このクエリが何かを返した場合に例外を発生させる on-insert/update トリガーを作成します。

SELECT *
FROM
  BRANCH B1
 ,BRANCH B2
 ,BRANCH B3
WHERE B1.PARENT_ID = :NEW.NEW_PARENT_ID
  AND B2.PARENT_ID = B1.BRANCH_ID
  AND B2.PARENT_ID = B3.BRANCH_ID;
于 2009-01-08T16:37:34.933 に答える