2つの列で値が重複しないようにテーブル制約を作成するにはどうすればよいですか?
-
06-07-2019 - |
質問
次の表があります:
CREATE TABLE [dbo].[EntityAttributeRelship](
[IdNmb] [int] IDENTITY(1,1) NOT NULL,
[EntityIdNmb] [int] NOT NULL,
[AttributeIdNmb] [int] NOT NULL,
[IsActive] [bit] NOT NULL CONSTRAINT [DF_EntityAttributeRelship_IsActive] DEFAULT ((0)),
CONSTRAINT [PK_EntityAttributeRelship] PRIMARY KEY CLUSTERED
([IdNmb] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
表のデータの一部は次のようになります:
IdNmb EntityIdNmb AttributeIdNmb IsActive
1 22 7 0
2 22 8 0
3 22 9 0
4 22 10 1
IsActive = 1のEntityIdNmbのレコードが既に存在する場合、IsActive = 1を持つレコードを誰も追加または更新しないように制約を追加します。
これを行うにはどうすればよいですか
解決
SQLServerを使用している場合、クラスター化されたインデックス付きビューを作成できます。
CREATE VIEW dbo.VIEW_EntityAttributeRelship WITH SCHEMABINDING AS
SELECT EntityIdNmb
FROM dbo.EntityAttributeRelship
WHERE IsActive = 1
GO
CREATE UNIQUE CLUSTERED INDEX UIX_VIEW_ENTITYATTRIBUTERELSHIP
ON dbo.VIEW_EntityAttributeRelship (EntityIdNmb)
これにより、テーブルにEntityIdNmbが1つだけあり、IsActive = 1になります。
他のヒント
トリガーを実装する必要があるように聞こえます(db製品がそれをサポートしていると仮定)。 1つのアクティブエントリと1つの非アクティブエントリのみが必要な場合は、一意のインデックスが機能します。それ以外の場合は、両方がアクティブである同じIDの2つのレコードが存在しないことを確認する何らかのカスタム制約またはトリガー(おそらく2-挿入用、更新用)を記述する必要があります。
MSSQLを使用している場合(構文は次のようになります)、IsActive = 1の行のみを含むビューを作成し、ビューのEntityIdNmbに一意のインデックスを配置します。
最近作業したPostgreSQLでは、部分インデックスを作成できます。 http://www.postgresql.org/docs/8.3/interactive/ indexs-partial.html
トリガーを作成する際に重要なのは、レコードを拒否するか、値を1ではなく0に変更するか、古いレコードをゼロに更新して、この1つをそのままにするかどうかを決定することです。値が1のレコードを削除する場合、別のレコードをアクティブなレコードに変更する必要がありますが、どのレコードを選択するのですか?トリガー内でやりたいことを定義できたら、プロセスの設計を改善できます。
後の2つのステップを実行して、任意のアドレスをデータベースのメインの住所にします。私たちのビジネスルールは1つであり、1つのアドレスのみがメインのアドレスになります。アドレスがある場合は、1つをメインのアドレスとしてマークする必要があります。この種のトリガーの鍵は、挿入/更新/削除がバッチで発生する可能性があることを覚えて(これが通常ではない場合でも)、トリガーがセットベースで機能することを確認することです。私がここに着いたとき、私たちのものはカーソルを介して複数行の処理を実装しました。これはインポートで200,000個のアドレスを更新しなければならなかったときに悪いこととなりました。 (未経験者への注意-トリガーでカーソルを使用しないでください!)
非アクティブなレコードは何に使用されますか?それらは未使用で、以前アクティブだったレコードを追跡するためだけにありますか?もしそうなら、データを複数のテーブルに分割することは可能でしょうか?次のようなもの...
EntityAttributeRelship(IDNmb、EntityIDNmb、AttributeIDNmb)
EntityAttributeRelshipHistory(IDNmb、EntityIDNmb、AttributeIDNmb)
EntityAttributeRelshipテーブルにある場合、アクティブです。履歴テーブルにある場合、ある時点でアクティブ化され、その後非アクティブ化されましたか?
1つのテーブルにすべてが必要な場合は、todd.runのトリガーを使用することをお勧めします。