4

2 つの列 ("Int_1" と "Int_2") に挿入しようとしている値が既に存在するレコードが存在する場合、レコードを挿入できないように、テーブルにチェック制約を実装しようとしています。例えば:

ID     Name     Int_1     Int_2
1      Dave       1         2

上記のテーブルに (2, Steve, 2, 2) を挿入することは (3, Mike, 1, 3) と同様に問題ありませんが、Int_1 と Int_2 が既に存在する場所に値を挿入することはできません。つまり、(4, Stuart, 1 、2) は違法です。

このようにテーブルを定義するとうまくいくと思いました:

CREATE TABLE [Table](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](255) NOT NULL,
    [Int_1] [int] NOT NULL,
    [Int_2] [int] NOT NULL,
    CONSTRAINT [chk_Stuff] CHECK (dbo.chk_Ints(Int_1, Int_2)=1))

ここで、dbo.chk_Ints が定義されています。

CREATE FUNCTION [dbo].[chk_Ints](@Int_1 int,@Int_2 int)
RETURNS int
AS
BEGIN

DECLARE @Result int

IF NOT EXISTS (SELECT * FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2)
BEGIN
    SET @Result = 1
END
ELSE 
BEGIN
    SET @Result = 0
END

RETURN @Result
END

GO

上記のコンボを使用する場合、任意のレコードを挿入しようとすると、SQL はチェック制約を破ったことを通知します。テーブルからすべての行を削除して最初のレコードを挿入しようとすると、SQL は制約を破ったことを通知します。

UDF が複数のテーブル列に依存するチェック制約の例を探して、かなり長い間インターネットを精査してきましたが、役に立ちませんでした。なぜこれがうまくいかないのかについてのアイデアはありますか?

前もって感謝します :)

4

1 に答える 1

14

はい、何が起こっているのかを理解するまで、これは不可解に思えるかもしれません。

挿入しようとしている行にある値に対して関数が呼び出されます。しかし、関数がどのように呼び出されるかを考えてみてください。それを呼び出すのがチェック制約です。

次に、渡されるパラメーターについて考えてみましょう。彼らはどこから来たのか?定義によると、チェック制約はそれらを列Int_1およびから取得しますInt_2

したがって、列の値として渡します。ただし、列の値は行に属している必要があります。この場合は何列目ですか?あなたが挿入しようとしているもの!

つまり、この時点で行挿入され、トランザクションのみが保留中です。それでも、行がテーブルにあるという事実は非常に重要です。なぜなら、それが関数によって検出され、1結果が報告されるからです。

したがって、何が起こっているかは次のとおりです。

  • 行を挿入しようとしている、

  • 関数その行を確認し、指定されたパラメーターを持つ行が既に存在することを示します。

  • チェック制約は、挿入を禁止することによってそれに応じて「反応」します。

  • 挿入はロールバックされます。

もちろん、すべてのことを理解しているので、重複をチェックする別のロジックを思い付くのは簡単です。基本的に、関数は、新しい行が既にテーブルにあることを「心に留めておく」必要があるため、テーブル内にその行が存在することが、確立したいルールに違反しているかどうかを判断しようとする必要があります。たとえば、指定されたパラメーターに一致する行を数え、結果が 1 以下かどうかを確認できます。

IF (SELECT COUNT(*) FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2) < 2
BEGIN
    SET @Result = 1
END
ELSE 
BEGIN
    SET @Result = 0
END

ただし、 @a_horse_with_no_name で提案されているように、このジョブのチェック制約で関数を使用するという全体的なアイデアは、2 つの列に一意の制約を追加するよりもはるかに劣っています。これを行う:

ALTER TABLE [Table]
ADD CONSTRAINT UQ_Table_Int1_Int2 UNIQUE (Int_1, Int_2);

重複を忘れることができます。

于 2013-09-24T13:04:08.347 に答える