Pokud se někdy ocitnete v situaci, kdy budete muset znovu povolit CHECK
omezení, které bylo dříve deaktivováno, měli byste se určitě ujistit, že víte, co děláte.
Zejména byste měli pochopit rozdíl mezi WITH NOCHECK
a WITH CHECK
argumenty.
Tyto argumenty lze použít v době, kdy povolíte omezení. Určují, zda jsou stávající data ověřována proti znovu aktivovanému (nebo nově přidanému) CHECK
omezení. V zásadě máte možnost zkontrolovat všechna existující data, zda nedošlo k porušení daného omezení. Pokud nic neurčíte, stávající data nebudou být zkontrolován. Proto je důležité pochopit, jak to funguje.
Mimochodem, tyto argumenty platí také pro omezení cizího klíče.
Jak můžete očekávat, WITH CHECK
určuje, že existující data jsou ověřena a WITH NOCHECK
upřesňuje, že není. Výchozí hodnota je WITH NOCHECK
.
Pokud používáte WITH NOCHECK
, bude omezení označeno jako nedůvěryhodné. Ve skutečnosti je to označeno jako nedůvěryhodné, když omezení deaktivujete. Ale když jej znovu povolíte, zůstane nedůvěryhodný, pokud nepoužijete WITH CHECK
. Jinými slovy, pokud chcete přeformulovat jeho „důvěryhodnost“, musíte to výslovně specifikovat.
Jinými slovy:
- Když použijete
WITH NOCHECK
, omezení zůstane nedůvěryhodné. - Když použijete
WITH CHECK
stane se důvěryhodným, ale pouze v případě, že všechna existující data budou vyhovovat omezení. Pokud některá existující data porušují omezení, omezení nebude povoleno a zobrazí se chybová zpráva.
Samozřejmě, když říkám „všechna existující data“, mám na mysli pouze data, na která se omezení vztahuje.
Mohou nastat scénáře, kdy jste záměrně zakázali omezení, protože jste museli zadat data, která omezení porušují. V takových případech, pokud neplatná data musí zůstat v databázi, budete muset použít WITH NOCHECK
pokud chcete omezení znovu povolit. To vám umožní povolit omezení, aniž by vám překážela jakákoli existující data.
Níže jsou uvedeny příklady, které to demonstrují.
Příklad 1 – Kontrola omezení CHECK
Nejprve použijeme sys.check_constraints
podívat se na všechny CHECK
omezení v aktuální databázi.
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Výsledek:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Vidíme, že jsou všechny povolené a důvěryhodné (protože všechny mají nuly v is_disabled a is_not_trusted sloupce).
Pro tento článek deaktivuji a znovu povolím chkJobTitle omezení.
Příklad 2 – Deaktivace omezení
Zde deaktivuji chkJobTitle omezení:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Hotovo.
Nyní si znovu projdeme všechna omezení:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Výsledek:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 1 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Vidíme, že byl deaktivován (protože jeho is_disabled sloupec je nastaven na 1 ).
Můžete si všimnout, že
is_not_trusted
sloupec je také nastaven na
1
. To znamená, že CHECK
omezení nebylo ověřeno systémem pro všechny řádky.
Jak již bylo zmíněno, CHECK
omezení lze věřit pouze v případě, že všechna data úspěšně splnila podmínky omezení. Když zakážeme omezení, otevře se tím potenciál pro vstup neplatných dat do databáze. Proto si nemůžeme být 100% jisti, že všechna data jsou platná, a proto je omezení označeno jako nedůvěryhodné.
Způsob, jak zajistit, aby bylo omezení opět důvěryhodné, je znovu jej povolit pomocí WITH CHECK
argument. To způsobí, že omezení zkontroluje všechna data, než bude znovu povoleno. Pokud jsou některá data neplatná, nebude možné je znovu povolit. Budete muset buď aktualizovat data, aby byla platná, nebo znovu povolit omezení pomocí WITH NOCHECK
argument místo toho (což způsobí, že omezení zůstane nedůvěryhodné).
Příklad 3 – Povolte omezení pomocí výchozích nastavení (S NOCHECK)
Pojďme znovu povolit omezení a spusťte dotaz znovu.
Abych omezení povolil, budu líný a použiji výchozí nastavení:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Nyní ověřte změnu:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Výsledek:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 1 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Viděl jsi, co se právě stalo? I když jsem omezení znovu povolil, stále není důvěryhodné.
Je to proto, že jsem byl líný (nebo možná jen zapomnětlivý), když jsem povolil omezení. Když jsem povolil omezení, zapomněl jsem zadat WITH CHECK
. Výchozí hodnota je WITH NOCHECK
což znamená, že existující data se při opětovném povolení omezení nekontrolují.
To je důvod, proč byste měli určitě vědět, co děláte, když povolíte CHECK
(a FOREIGN KEY
) omezení. Tím, že jsme líní a explicitně nespecifikujeme potenciálně důležité nastavení, dáváme SQL Serveru oprávnění zavírat oči před jakýmikoli problémy se stávajícími daty.
Pokud však celý důvod, proč jste potřebovali deaktivovat omezení, je vložit data, která omezení porušují, pak výchozí WITH NOCHECK
je pravděpodobně to, co chcete.
Mimochodem, pro nová omezení je výchozí nastavení WITH CHECK
.
V mém případě jsem však žádné nevložil ani neaktualizoval data po deaktivaci omezení, takže pokud byla důvěryhodná dříve, měla by být důvěryhodná i nyní.
Jak tedy mohu svému omezení znovu důvěřovat?
Příklad 4 – Povolte omezení pomocí WITH CHECK
Pokud chci, aby mé omezení bylo opět důvěryhodné, musím výslovně zadat WITH CHECK
při jeho opětovné aktivaci.
Znovu deaktivujeme omezení:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Takže teď jsem zpátky tam, kde jsem byl předtím, než jsem to znovu povolil.
Co jsem měl udělat, když jsem to znovu povolil, bylo toto:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Nyní se znovu podívejte na omezení:
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Výsledek:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Fuj! Moje omezení je opět důvěryhodné.
Příklad 5 – Povolte omezení CHECK s neplatnými daty
Moje omezení je samozřejmě opět důvěryhodné, protože jsem nevložil neplatná data, když bylo zakázáno. Kdybych to udělal, nemohl bych to povolit pomocí WITH CHECK
, jak je ukázáno níže.
Pokud jej znovu zakážu:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Nyní vložte neplatná data (a vraťte výsledky):
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Výsledek:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Úspěšně jsme tedy vložili neplatná data (poslední řádek).
Toto je neplatné, protože definice omezení je následující:([JobTitle]<>'Digital Nomad')
To znamená, že
JobTitle
sloupec nesmí obsahovat text Digital Nomad
.
Nyní se pokusíme znovu povolit CHECK
omezení pomocí WITH CHECK
a uvidíte, co se stane.
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Výsledek:
Msg 547, Level 16, State 0, Line 1 The ALTER TABLE statement conflicted with the CHECK constraint "chkJobTitle". The conflict occurred in database "Test", table "dbo.Occupation", column 'JobTitle'.
Nemůžeme tedy znovu aktivovat omezení pomocí WITH CHECK
zatímco v tabulce máme data, která porušují CHECK
omezení. Buď potřebujeme aktualizovat data, nebo musíme použít WITH NOCHECK
(nebo jej jednoduše úplně vynechat).
Zkusme to znovu pomocí WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Výsledek:
Commands completed successfully. Total execution time: 00:00:00.015
Takže můžeme úspěšně aktivovat omezení, pokud nezkontrolujeme existující data.
Samozřejmě v tomto případě CHECK
omezení stále není důvěryhodné. Pokud chceme, aby omezení bylo důvěryhodné, budeme muset aktualizovat data, aby omezení neporušovala.
Příklad:
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Výsledek:
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Nyní můžeme změnit CHECK
omezení, abyste se znovu stali důvěryhodnými.
Udělejme všechny tři společně:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle; ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle; SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Výsledek:
+-----------------+---------------+------------------+----------------------------------------+ | name | is_disabled | is_not_trusted | definition | |-----------------+---------------+------------------+----------------------------------------| | chkPrice | 0 | 0 | ([Price]>(0)) | | chkValidEndDate | 0 | 0 | ([EndDate]>=[StartDate]) | | chkTeamSize | 0 | 0 | ([TeamSize]>=(5) AND [TeamSize]<=(20)) | | chkJobTitle | 0 | 0 | ([JobTitle]<>'Digital Nomad') | +-----------------+---------------+------------------+----------------------------------------+
Takže nyní je naše omezení opět aktivní a důvěryhodné a naše databáze je bez digitálních nomádů!