Sql制約メソッドは偽の値を返します

SQLの制約メソッドに問題があります。

これは私のテーブルです

CREATE TABLE [relations].[CompoundKey_Contacts](
    [compoundId] [varchar](32) NOT NULL,
    [companyId] [varchar](32) NULL,
    [personId] [varchar](32) NULL,
    [contactInfoId] [varchar](32) NOT NULL)

この表に行を追加すると、その人と会社のこの組み合わせがまだ表に存在していないことを確認する必要があります。このため私は制約関数を使用します

制約

ALTER TABLE [relations].[CompoundKey_Contacts]  WITH NOCHECK ADD  CONSTRAINT [CK_CompoundKey_Contacts] CHECK  (([relations].[doesThisCompoundKeyExist]([personId],[companyId])='NO'))
GO

ALTER TABLE [relations].[CompoundKey_Contacts] CHECK CONSTRAINT [CK_CompoundKey_Contacts]
GO

機能

CREATE function [relations].[doesThisCompoundKeyExist](
    @personId varchar(32),
    @companyId varchar(32)
)
returns varchar(3)
as
begin
    declare @exists varchar(32)

    if(@companyId is null and @personId is null)
      set @exists = 'YES'
    else if(@personId is null)
        if exists(select compoundId from relations.CompoundKey_Contacts where personId is null AND companyId = @companyId)
            set @exists = 'YES' 'This is where to code enters, but it should come to the else and return 'NO'
        else
            set @exists = 'NO'
    else if(@companyId is null)
        if exists(select compoundId from relations.CompoundKey_Contacts where personId = @personId AND companyId is null)
            set @exists = 'YES'
        else
            set @exists = 'NO'
    else if exists(
        select compoundId from relations.CompoundKey_Contacts where personId = @personId AND companyId = @companyId
        )
        set @exists = 'YES'
    else
        set @exists = 'NO'
    return @exists
end;

挿入文が失敗する

insert into relations.CompoundKey_Contacts (companyId, contactInfoId, personId, compoundId) values ('COM-000015945', 'INF-000144406', null, 'CPK-000000067');

問題はこれです。一意の挿入を持つテーブルに挿入を実行すると、それでも失敗します。私はもちろん、それがselectステートメントで一意であることを確認しています。ここで面白い部分が来る。私はそれをデバッグし、それが失敗した場所をチェックし、そのコード部分を分解し、関数内になければ自由に実行します。そうする必要がありますので、次のコードは関数内で実行されないと動作します

if exists(select compoundId from relations.CompoundKey_Contacts where personId is null AND companyId = 'COM-000015945')
                print 'YES'
            else
                print 'NO' 'Returns NO as it should.

これはエラーメッセージです。

The INSERT statement conflicted with the CHECK constraint "CK_CompoundKey_Contacts". The conflict occurred in database "domas", table "relations.CompoundKey_Contacts".
The statement has been terminated.

私はこれをSql Server 2012とSql Server 'DENALI' CTP3の両方で実行します

0
@gbn私のテーブルに(人、会社)の組み合わせの重複を避けようとしています。同じ(人物、会社)を挿入しようとすると新しい挿入物が失敗するはずだが、別のキー
追加された 著者 Marthin,
私は実際に英語でやってみようとしているので、コードを解読する必要はありません
追加された 著者 gbn,

2 答え

チェック制約でUDFを使用すると、わかるように確実に動作しません

余分なロジックが必要な場合は、計算列にユニーク制約を使用してください

ALTER TABLE CompoundKey_Contacts
    ADD CompoundKey AS ISNULL(personID, 'NOPERSONID') + ISNULL(companyId, 'NOCOMPANYID');
ALTER TABLE CompoundKey_Contacts WITH CHECK
    ADD CONSTRAINT UQ_CompoundKey_Contacts_CompoundKey UNIQUE (CompoundKey);

または、単純な一意の制約

ALTER TABLE CompoundKey_Contacts WITH CHECK
    ADD CONSTRAINT UQ_CompoundKey_OtherUnique UNIQUE (personID, companyId);
4
追加された
チェック制約のUDFがなぜ機能しないのかについて、簡単な答えを教えてください。私はその部分を得ていませんでした。
追加された 著者 Marthin,
@マーティン:申し訳ありませんが、これを参照してください stackoverflow.com/questions/7756268/…
追加された 著者 gbn,

personId、companyId にユニーク制約またはユニークなインデックスを作成します。

とにかく正しいことを得るのが非効率的で困難なので、UDFでチェック制約を使用しないでください。

2
追加された