2009-03-09 9 views
3

私は、次の表があります。私は必ず誰も追加していないまたは更新することにするために制約を追加したい2つの列に重複する値を防ぐためにテーブル制約を作成するにはどうすればよいですか?

IdNmb EntityIdNmb AttributeIdNmb IsActive 
1  22    7    0 
2  22    8    0 
3  22    9    0 
4  22    10    1 

:この何かのように見えます

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] 

にテーブル内のデータの一部をIsActive = 1であるEntityIdNmbのレコードが既に存在する場合、IsActive = 1を持つレコード。

どのようにすればいいですか?

+0

@Eric、時間が許せば、なぜクラスタリングされたビューソリューションtomfutと私はあなたの要求を満足していないのですか?私はCI Viewsをこの種の問題に対する洗練された解決策と考えています。 –

+0

@Lievenと@tomfut、私はこれを行うためのトリガーを作成しましたが、私はあなたの答えを最初に誤解していたので、私もあなたの解決策を試みます。ありがとうございました。 –

答えて

6

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) 

これはのisActiveとあなたのテーブルで唯一のEntityIdNmbがありますが保証= 1

+0

これは動作しません。私はIsActive = 1のレコードだけでなく、すべてのレコードを返す必要があります。 –

+0

@エリック、それを試しても私のことを本当に落としましたか?それはあなたが尋ねることを行います。「IsActive = 1のレコードを追加または更新する人はいません。すでにIsActive = 1のEntityIdNmbのレコードがある場合」 –

+0

私は謝罪します。私はdownvoteを削除しました。私はあなたの答えを誤解しました。私はあなたが私のデータを取得するためにビューを使用するよう指示していると思いました。 –

3

トリガーを実装する必要があるようです(db製品がサポートしているとします)。 1つのアクティブなエントリと1つの非アクティブなエントリだけが必要な場合は、ユニークなインデックスが機能します。それ以外の場合は、何らかのカスタム制約やトリガを挿入する必要があります(挿入の場合は2つ、更新の場合はおそらく2つ)。両方ともアクティブな同じIDを持つ2つのレコードがないことを確認します。

+0

私のトリガーに何を書き込むかについてより多くの洞察を提供できますか?ロールバックを実行するのですか? –

+0

エリック、競合がある場合は、例外をスローします。トリガーはストアドプロシージャと大きく異なるわけではありません。データベースを実行するタイミングをdbが知るように、トリガーは異なる方法で登録するだけです。 –

0

非アクティブレコードはどのように使用されますか?それらは未使用であり、過去に活発な記録を記録するだけであるか?もしそうなら、複数のテーブルにデータを分割することは可能でしょうか?以下のような何か...

EntityAttributeRelship(IDNmb、EntityIDNmb、AttributeIDNmb)

EntityAttributeRelshipHistory(IDNmb、EntityIDNmb、AttributeIDNmb)

それはEntityAttributeRelshipテーブルにいた場合、それは有効だ

。それが履歴テーブルにあれば、それはある時点で有効化されて以来、無効化されていますか?

すべてのテーブルが必要な場合は、トリガーを使用するというtodd.runの提案に従います。

+0

私は1つのテーブルにすべてが必要です。それは既存のテーブルであり、データは既にそこにあります。私は制約を追加するだけです。トリガーが必要な場合は、わかりやすく、何を書くかを知る必要があります。 –

2

あなたはMSSQLを使用している場合は(私はそれがあなたの構文がどのように見えるかだと思う)、との行のみを含むビューを作成します。 IsActive = 1とし、ビュー内のEntityIdNmbにユニークなインデックスを設定します。私は最近になってと、あなたは部分インデックスを作成することができます働いてきたのPostgreSQLでは、

http://www.postgresql.org/docs/8.3/interactive/indexes-partial.html

+0

@tomfut、あなたは私が持っていたのと同じアイデアを持っているようです。何らかの理由で、OPの要求を満足していません。 –

+0

@リーブン、そしてあなたの答えは、最初と詳細です!スパムのために申し訳ありません。 Belairは、元のテーブルではなく、ビューからSELECTSを実行する必要があることを示すために答えを得ているようです。 –

+0

@tomfut、害はありません。おそらく、あなたはその見解から選択することについてあなたの前提に合っているでしょう。 @Belair、これを読まなければならないとすれば、その仮定は真実ではない。元のテーブルに選択、更新、挿入するだけです。 CIビューは制約を処理します。 –

1
トリガーを書いてあるものは、あなたが、レコードを拒否する値を変更するかどうかを決定することである

0の代わりに0を使用するか、古いレコードをゼロに更新して、これを1にすることができます。 1の値を持つレコードを削除する場合は、別のレコードをアクティブなものに変更する必要がありますか、どのレコードを選択するのですか?引き金の中でやりたいことを定義できたら、プロセスの設計をより良くすることができます。

私たちは後者の2つのステップを実行して、任意のアドレスをデータベースのメインの郵送先アドレスにします。私たちのビジネスルールは1つで、メインアドレスは1つだけです。アドレスがある場合は、メインアドレスとしてマークする必要があります。この種のトリガーの鍵は、挿入/更新/削除がバッチで(たとえこれが標準ではないにしても)発生する可能性があることと、トリガーがセットベースの方法で動作することを確認することです。私がここに来たとき、私たちはカーソルで複数行の処理を実装しましたが、これはインポートで20万のアドレスを更新する必要があるときに悪いことになりました。(経験の浅い人には注意してください。)

関連する問題