1

私はスキーマ以下の通りですテーブルaccessを持っている:許可Unique制約とCheck制約を関連付けることは可能ですか?

create table access (
    access_id int primary key identity, 
    access_name varchar(50) not null, 
    access_time datetime2 not null default (getdate()), 
    access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')), 
    access_message varchar(100) not null, 
) 

アクセスタイプのみがOUTER_PARTY and INNER_PARTYです。

私が達成しようとしているのは、INNER_PARTYの入力は、ログイン(ユーザ)ごとに1回だけでなければならないが、OUTER_PARTYは何回でも記録できます。だから私は、それを直接行うことが可能かどうか、またはこの種の制限を作成するためのイディオムがあるかどうか疑問に思っていました。

私はこの質問をチェックしました:Combining the UNIQUE and CHECK constraintsですが、それは別のものを目指していたので私の状況に適用できませんでした。

+0

感謝を。私は愚かにそれを質問に入れました。 'access_type'にクラスタード・インデックスを作成するのは正しいですか?また、ビューを作成した場合、基になるテーブルを更新することはできません。私が間違っていない場合は、トリガーの代わりにトリガーを使用してビューを更新する必要がありますが、それは複雑になります。 – Animesh

+0

@Damien_The_Unbeliever - (クリーンアップされたコメント)合意。答えが示すように、インデックス付きのビューを使用する必要はありません。 –

答えて

6

フィルターユニーク索引が表に追加することができます検討する@access_timeをフォーマットする必要があります。このインデックスは、access_time列から時間コンポーネントを削除する計算列に基づくことができます。

create table access (
    access_id int primary key identity, 
    access_name varchar(50) not null, 
    access_time datetime2 not null default (SYSDATETIME()), 
    access_type varchar(20) check (access_type in ('OUTER_PARTY','INNER_PARTY')), 
    access_message varchar(100) not null, 
    access_date as CAST(access_time as date) 
) 
go 
create unique index IX_access_singleinnerperday on access (access_date,access_name) where access_type='INNER_PARTY' 
go 

に動作するようです:タグの

--these inserts are fine 
insert into access (access_name,access_type,access_message) 
select 'abc','inner_party','hello' union all 
select 'def','outer_party','world' 
go 
--as are these 
insert into access (access_name,access_type,access_message) 
select 'abc','outer_party','hello' union all 
select 'def','outer_party','world' 
go 
--but this one fails 
insert into access (access_name,access_type,access_message) 
select 'abc','inner_party','hello' union all 
select 'def','inner_party','world' 
go 
+0

Damien: getdate()の代わりにsysdatetime()を使用した理由はありますか? sysdatetimeはより多くのストレージを必要としませんか? – Animesh

+0

@KishorNanda - ストレージはデータ型に依存します。あなたのケースでは 'datetime2'なので、余分な精度は「フリー」です –

+0

ああそうです。あなたの答えは私のためにうまくいっていて、インデックスの理解も良くなっていました。ありがとうございました。 – Animesh

2

残念ながら、チェック制約に「if」を追加することはできません。私はトリガを使用しての助言:

create trigger myTrigger 
on access 
instead of insert 
as 
begin 
    declare @access_name varchar(50) 
    declare @access_type varchar(20) 
    declare @access_time datetime2 

    select @access_name = access_name, @access_type= access_type, @access_time=access_time from inserted 

    if exists (select 1 from access where [email protected]_name and [email protected]_type and [email protected]_time) begin 
    --raise excetion 
    end else begin 
    --insert 
    end 
end 

日付のみ一部

+0

これは失敗し、複数の挿入またはスナップショットの分離のために重複を許可します。ロジックが正しいようにSQL Serverに制約を適用させる方がよいでしょう。また、あなたは更新について忘れてしまった。 –

+0

私は人々がなぜトリガーに反対しているのか分かりません。必要に応じて複数の挿入を処理するように変更できます。挿入されたテーブルをループするだけです。この場合、SQL Serverでどのように制約を適用するのですか。それが問題の全体のポイントです。 – Diego

+0

ビューの一意制約を使用します。トリガーは効率が低く、正しいとは思われません。 –

関連する問題