V SQL Server můžete vytvořit CHECK
omezení v tabulce k určení hodnot dat, které jsou přijatelné v jednom nebo více sloupcích.
Pokud tabulka obsahuje CHECK
omezení a vy se pokoušíte poskytnout data, která neodpovídají CHECK
omezení, operace selže s chybou.
To pomáhá udržovat integritu dat, protože to pomáhá zabránit vstupu neplatných dat do databáze.
Když vytvoříte CHECK
omezení, zadáte logický výraz, který vrátí TRUE
nebo FALSE
. Tento logický výraz se používá ke kontrole dat.
CHECK
omezení jsou podobná omezením cizího klíče, protože řídí hodnoty, které se vkládají do sloupce. Rozdíl je však v tom, jak určují, které hodnoty jsou platné:Omezení cizího klíče získávají seznam platných hodnot z jiné tabulky, zatímco CHECK
omezení určují platné hodnoty z logického výrazu.
Omezení lze definovat na úrovni sloupců nebo tabulky. Omezení na úrovni sloupce platí pouze pro data v tomto sloupci. Omezení na úrovni tabulky platí pro celý řádek a kontroluje data z více sloupců.
Níže jsou uvedeny příklady vytváření CHECK
na úrovni sloupců i na úrovni tabulky omezení.
Příklad 1 – Vytvoření omezení KONTROLY na úrovni sloupců
Zde je příklad vytvoření základního CHECK
na úrovni sloupce omezení v době vytváření tabulky.
CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL, CONSTRAINT chkPrice CHECK (Price > 0) );
V tomto případě CHECK
omezení určuje, že všechna data v Price
musí být větší než 0. Jinými slovy, cena nemůže být nula ani záporná. Toto je omezení na úrovni sloupců, protože se vztahuje na data v jednom sloupci.
Protože se jedná o omezení na úrovni sloupce, mohl jsem ho definovat jako součást sloupce (bez čárky). Takže jsem mohl udělat toto:
CREATE TABLE ConstraintTest ( ConstraintTestId int IDENTITY(1,1) NOT NULL PRIMARY KEY, Price smallmoney NOT NULL CONSTRAINT chkPrice CHECK (Price > 0) );
Ať tak či onak, zkusme vložit neplatnou hodnotu:
INSERT INTO ConstraintTest ( Price ) VALUES ( 0 );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkPrice". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'Price'.
Příklad 2 – Přidat další sloupce a další omezení KONTROLY na úrovni sloupců
Pojďme do naší tabulky přidat další sloupce a poté přidat další CHECK
na úrovni sloupce omezení.
ALTER TABLE ConstraintTest ADD TeamSize tinyint NOT NULL, StartDate date NOT NULL, EndDate date NOT NULL, CONSTRAINT chkTeamSize CHECK (TeamSize >= 3 AND TeamSize <= 15) ;
Jeden z nových sloupců zaznamenává počet členů týmu. V tomto případě platí obchodní pravidlo, že tým musí mít alespoň 3 členy, ale ne více než 15. Databáze by proto měla zabránit situaci, kdy má tým méně než 3 členy nebo více než 15.
Zkusme vložit neplatnou hodnotu:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 2, '2020-01-01', '1900-02-02' );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Příklad 3 – Přidání omezení KONTROLY na úrovni tabulky
Nyní přidáme omezení na úrovni tabulky. Tím zkontrolujete data ve dvou sloupcích.
Mimochodem, k přidání CHECK
nemusíte přidávat další sloupec omezení. Omezení můžete jednoduše přidat samo.
Příklad:
ALTER TABLE ConstraintTest ADD CONSTRAINT chkValidEndDate CHECK (EndDate >= StartDate) ;
V tomto případě přidávám omezení, které zajistí, že datum ukončení nemůže být nikdy dřívější než datum zahájení. Toto je kontrola dat ve dvou sloupcích, a proto je to omezení na úrovni tabulky.
Zkuste vložit neplatnou hodnotu:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 3, '2020-01-01', '1900-02-02' );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".
Všimněte si, že abych otestoval toto omezení, musel jsem zvýšit počet členů týmu na 3, abych zabránil spuštění předchozího omezení jako první (CHECK
omezení jsou ověřována v pořadí, v jakém jsou vytvořena).
Příklad 4 – Změňte omezení KONTROLY
Ve skutečnosti nemůžete změnit CHECK
omezení. Pokud ji potřebujete změnit, budete ji muset vypustit a vytvořit ji s novou definicí.
Příklad:
ALTER TABLE ConstraintTest DROP CONSTRAINT chkTeamSize; ALTER TABLE ConstraintTest ADD CONSTRAINT chkTeamSize CHECK (TeamSize >= 5 AND TeamSize <= 20) ;
Jak již bylo zmíněno, CHECK
omezení jsou ověřována v pořadí, v jakém jsou vytvořena, takže to může ovlivnit, která chyba je zachycena jako první.
Pokud se tedy v tomto případě pokusím vložit neplatnou hodnotu (a také zahrnout neplatná data), neplatná data budou zachycena jako první:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, '2020-01-01', '1900-02-02' );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkValidEndDate". The conflict occurred in database "Test", table "dbo.ConstraintTest".
Abych tedy mohl zkontrolovat své nejnovější omezení, musím nejprve opravit problém s datem:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 4, '2020-01-01', '2020-02-02' );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Moje nejnovější omezení tedy funguje podle očekávání.
Příklad 5 – ZKONTROLUJTE omezení a sloupce IDENTITY
Nyní, když jsme otestovali omezení, pojďme do toho a vložíme platná data:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 1, 5, '2020-01-01', '2020-02-02' );
Výsledek:
+--------------------+---------+------------+-------------+------------+ | ConstraintTestId | Price | TeamSize | StartDate | EndDate | |--------------------+---------+------------+-------------+------------| | 13 | 1.0000 | 5 | 2020-01-01 | 2020-02-02 | +--------------------+---------+------------+-------------+------------+
Nakonec získáme úspěšnou vložku.
Všimněte si však, že IDENTITY
sloupec se již zvýšil na 13.
Pamatujte, že když jsem poprvé vytvořil tabulku, definoval jsem ConstraintTestId
použít IDENTITY(1,1)
, což znamená, že by měl začínat na 1 a automaticky se zvyšovat o 1 s každým vložením řádku.
Ale teď, když jsem konečně vložil svůj první řádek, hodnota je již 13. Je to proto, že IDENTITY
sloupec se zvýší, i když CHECK
omezení způsobí INSERT
operace se nezdaří.
Všimněte si, že při vymýšlení příkladů pro tento článek jsem udělal několik dalších neúspěšných vložek, takže hodnota vzrostla na vyšší hodnotu, než jakou získáte, pokud budete jednoduše postupovat podle tohoto článku krok za krokem.
V každém případě udělejme poslední neúspěšné vložení a poté úspěšné, abychom to potvrdili.
Vložení se nezdařilo:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 4, '2020-01-02', '2020-02-03' );
Výsledek:
Msg 547, Level 16, State 0, Line 1 The INSERT statement conflicted with the CHECK constraint "chkTeamSize". The conflict occurred in database "Test", table "dbo.ConstraintTest", column 'TeamSize'.
Úspěšné vložení:
INSERT INTO ConstraintTest ( Price, TeamSize, StartDate, EndDate ) VALUES ( 2, 6, '2020-01-02', '2020-02-03' ); SELECT * FROM ConstraintTest;
Výsledek:
+--------------------+---------+------------+-------------+------------+ | ConstraintTestId | Price | TeamSize | StartDate | EndDate | |--------------------+---------+------------+-------------+------------| | 13 | 1.0000 | 5 | 2020-01-01 | 2020-02-02 | | 15 | 2.0000 | 6 | 2020-01-02 | 2020-02-03 | +--------------------+---------+------------+-------------+------------+
Vidíme, že IDENTITY
sloupec skočí z 13 na 15, takže se zjevně zvýšil během neúspěšného vložení.
Některá omezení omezení CHECK
Zde je několik omezení, na která je třeba pamatovat při práci s CHECK
omezení:
- Podmínka vyhledávání se musí vyhodnotit jako booleovský výraz a nemůže odkazovat na jinou tabulku.
- Výraz nemůže obsahovat datové typy aliasů.
CHECK
omezení nelze definovat pro text , ntext nebo obrázek sloupce.