行の他の値に基づいて、列に許可される値を制限することは可能ですか?
たとえば、私のテーブル:
ID Test_mode Active
-- --------- ------
1 1 Null
2 0 1
3 1 0
Test_mode
がActive
に挿入されている場合、0
の値を1
に変更する方法はありますか
OR
Test_mode
が1の場合、Active
の挿入/更新は許可されません
OR
Test_mode
が1で、Active
の挿入/更新が試みられた場合、何らかのエラーをスローします。
Active
はNULL、1、0、およびTest_mode
を0として1のみにすることができます。
知らない場合は、これが理にかなっていると思います。質問を更新します。
まず、dba.stackexchange.comへようこそ。投稿ありがとうございます。
行の他の値に基づいて、列に許可される値を制限することは可能ですか?
はい CHECK CONSTRAINTS を使用 ここ
例:
create table myTable (ID int identity(1,1)
, Test_mode int
, Active int
)
go
-- Active can only be NULL, 1, 0, AND only 1 with Test_mode as 0.
ALTER TABLE myTable WITH CHECK ADD
CONSTRAINT ck_active CHECK (active IS NULL OR active IN (1, 0))
go
-- some test data
insert into myTable (test_mode, Active) values (1, null)
insert into myTable (test_mode, Active) values (0, null)
insert into myTable (test_mode, Active) values (1, 0)
insert into myTable (test_mode, Active) values (0, 1)
insert into myTable (test_mode, Active) values (1, 1)
select * from myTable
-- Is there a way to either change the value of Test_mode to 0 if a 1 is inserted into Active
update myTable
set Test_mode = case when Active = 1 then 0
else Test_mode
end
where Active = 1
Test_mode
is 1はActiveの挿入/更新を許可しません--OR-- Test_modeが1で、Activeの挿入/更新が試行された場合、何らかのエラーをスローします。
説明どおりにTRY/CATCHを使用 ここ
無効なデータがテーブルに入るのを防ぐ最初の防御策は、列のデータ型です。
プロセスが列をデータ型の範囲外の値に挿入または更新しようとした場合(または列がNULL
sを許可していない場合はNULL
)、操作は即座に失敗します。追加の作業を行うため。
データ型の選択は、テーブル設計の最も重要な側面の1つです。
それで、あなたはスキーマを投稿しなかったので、あなたが提供した情報に基づいてスキーマを構築します:
CREATE TABLE [dbo].[Tests]
(
ID int IDENTITY(1, 1) PRIMARY KEY,
Test_mode bit NOT NULL, /* Based on only seeing 0/1. Maybe tinyint? */
Active bit NULL
);
この設計に基づいて、使用可能な組み合わせはすでに以下に制限されています。
Test_mode Active 0 NULL 0 0 0 1 1 NULL 1 0 1 1
それ以外の場合はエラーが発生します。 (これは良いことです。)
Activeに1が挿入された場合にTest_modeの値を0に変更する方法はありますか
OR
Test_modeが1の場合、Activeの挿入/更新を許可しない
OR
Test_modeが1で、Activeの挿入/更新が試行された場合、何らかのエラーをスローします。
ActiveはNULL、1、0、およびTest_modeが0の1のみです。
4値の許容される組み合わせ(まあ、一種)に到達するためのさまざまな方法を指定しました。これらは非常に異なる戦略であり、実装動作は非常に異なります。
私は、いわゆるdeclarative制約を使用することを好みます。つまり、テーブルスキーマとそれに関連付けられたオブジェクトは、許可される値を明示的にdeclaring許可することで制限します(または、場合によってはnot許可することです)。実際、列のデータ型自体は一種の宣言的制約です。値を制限できるのはテーブルデータに近いほど、制限を簡単かつ確実に行うことができます。 (対照的に、non-declarativeまたはactive制約は、T-SQLの一部、通常はテーブルトリガー、またはストアドプロシージャの一部を記述することによって実装されます。 )
オプションの最初の3つは、非宣言的な手段でのみ実装できます。ただし、最後の1つは宣言型なので、それに焦点を当てましょう。
Active
はNULL、1、0、およびTest_mode
を0とする1のみにすることができます。
これは実際に必要なものを定義します。これは、テーブル内の値の許可された組み合わせです。有効な組み合わせは、列の値同じ行内にのみ依存することに注意してください。これは、制約を実装するために使用できるメカニズムを決定するため、重要です。
この場合、 CHECK
constraint を使用できます。これは、行が有効か無効かをrow'sに基づいて判断するtrue/falseテストです。列の値1。テストが失敗した場合、行を変更しようとした操作はエラーで失敗します。
ALTER TABLE [dbo].[Tests] WITH CHECK
ADD CONSTRAINT CC_Tests_TestMode_Active
CHECK ((Test_mode != 0) OR ((Active IS NOT NULL) AND (Active = 1)));
Test_mode
が実際には(nullにできない)整数型であっても機能し続けるように述語を作成したことに注意してください。 CHECK
制約は、述語がundefined
と評価される行を許可するため、IS NOT NULL
部分が必要です。
1 これらはcanを使用して現在の行の外側でチェックを行いますが、これは悪い習慣であり、ここでは詳しく説明しません。代わりにトリガーを使用してください。
CREATE UNIQUE INDEX [UNQ_IndexName]
ON [dbo].[Table]([Column])
WHERE ([Status] in( 'A','D' ) );