sql >> Databáze >  >> RDS >> Sqlserver

Co byste měli vědět o WITH NOCHECK při povolení omezení CHECK v SQL Server

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ů!


  1. Jak uzavřít mezeru ve zranitelnosti v PostgreSQL

  2. Ormlite nebo sqlite Který z nich je dobrý pro Android?

  3. Funkce oken a další místní agregace

  4. Sémantika ResultSet#getDate().