sql >> Databasteknik >  >> RDS >> Sqlserver

Vad du bör veta om MED NOCHECK när du aktiverar en CHECK-begränsning i SQL Server

Om du någon gång hamnar i den situationen att du behöver återaktivera en CHECK begränsning som tidigare har inaktiverats, bör du definitivt se till att du vet vad du gör.

I synnerhet bör du förstå skillnaden mellan WITH NOCHECK och WITH CHECK argument.

Dessa argument kan användas när du aktiverar begränsningen. De anger huruvida befintliga data är validerade mot din återaktiverade (eller nyligen tillagda) CHECK begränsning. I grund och botten har du möjlighet att kontrollera alla befintliga data för eventuella överträdelser mot begränsningen. Om du inte anger någonting, gör det inte befintliga data kontrolleras. Det är därför det är viktigt att förstå hur det fungerar.

Förresten, dessa argument gäller även för främmande nyckelbegränsningar.

Som du kanske förväntar dig, WITH CHECK anger att befintlig data är validerad och WITH NOCHECK anger att det inte är det. Standard är WITH NOCHECK .

Om du använder WITH NOCHECK , kommer begränsningen att flaggas som otillförlitlig. Egentligen flaggas den som opålitlig när du inaktiverar begränsningen. Men när du återaktiverar den förblir den opålitlig om du inte använder WITH CHECK . Med andra ord, om du vill upprepa dess "tillförlitlighet", måste du uttryckligen ange detta.

Med andra ord:

  • När du använder WITH NOCHECK , kommer begränsningen att förbli opålitlig.
  • När du använder WITH CHECK det kommer att bli tillförlitligt, men bara om all befintlig data överensstämmer med begränsningen. Om någon befintlig data bryter mot begränsningen kommer begränsningen inte att aktiveras och du får ett felmeddelande.

När jag säger "all befintlig data" syftar jag naturligtvis bara på data som begränsningen gäller.

Det kan finnas scenarier där du avsiktligt inaktiverade en begränsning eftersom du var tvungen att ange data som bryter mot begränsningen. I sådana fall, om den ogiltiga informationen måste finnas kvar i databasen, måste du använda WITH NOCHECK om du vill återaktivera begränsningen. Detta gör att du kan aktivera begränsningen utan att någon befintlig data kommer i vägen.

Nedan finns exempel som visar detta.

Exempel 1 – Granska begränsningar för kontroll

Låt oss först använda sys.check_constraints för att ta en titt på alla CHECK begränsningar i den aktuella databasen.

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Resultat:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Vi kan se att de alla är aktiverade och betrodda (eftersom de alla har nollor i is_disabled och is_not_trusted kolumner).

För den här artikeln kommer jag att inaktivera och återaktivera chkJobTitle begränsning.

Exempel 2 – Inaktivera begränsningen

Här inaktiverar jag chkJobTitle begränsning:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Klart.

Låt oss nu granska alla begränsningar igen:

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Resultat:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Vi kan se att den har inaktiverats (eftersom den är_inaktiverad kolumnen är inställd på 1 ).

Du kanske märker att is_not_trusted kolumnen är också inställd på 1 . Detta indikerar att CHECK begränsning har inte verifierats av systemet för alla rader.

Som nämnts, en CHECK begränsning kan endast litas på om all data har klarat begränsningens villkor. När vi inaktiverar en begränsning öppnar detta upp möjligheten för ogiltig data att komma in i databasen. Därför kan vi inte vara 100 % säkra på att all data är giltig, varför begränsningen flaggas som otillförlitlig.

Sättet att säkerställa att begränsningen är betrodd igen är att återaktivera den med hjälp av WITH CHECK argument. Detta gör att begränsningen kontrollerar all data innan den återaktiveras. Om någon data är ogiltig kommer den inte att kunna återaktiveras. Du måste antingen uppdatera data så att den är giltig eller återaktivera begränsningen med hjälp av WITH NOCHECK argument istället (vilket gör att begränsningen förblir opålitlig).

Exempel 3 – Aktivera begränsningen med hjälp av standardinställningarna (med nock)

Låt oss återaktivera begränsningen och köra frågan igen.

För att aktivera begränsningen kommer jag att vara lat och använda standardinställningarna:

ALTER TABLE Occupation  
CHECK CONSTRAINT chkJobTitle; 

Verifiera nu ändringen:

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Resultat:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Såg du vad som just hände? Även om jag aktiverade begränsningen igen, är den fortfarande inte betrodd.

Detta beror på att jag var lat (eller kanske bara glömsk) när jag aktiverade begränsningen. När jag aktiverade begränsningen glömde jag att ange WITH CHECK . Standard är WITH NOCHECK vilket innebär att befintlig data inte kontrolleras när begränsningen återaktiveras.

Det är därför du definitivt bör veta vad du gör när du aktiverar CHECK (och FOREIGN KEY ) begränsningar. Genom att vara lata och inte explicit specificera en potentiellt viktig inställning ger vi SQL Server tillåtelse att blunda för eventuella problem med befintlig data.

Men om hela anledningen till att du behövde inaktivera begränsningen är att infoga data som bryter mot begränsningen, är standard WITH NOCHECK är förmodligen vad du vill.

Förresten, för nya begränsningar är standardvärdet WITH CHECK .

Men i mitt fall har jag inte infogat eller uppdaterat någon data efter att ha inaktiverat begränsningen, så om det var pålitligt tidigare borde det fortfarande vara pålitligt nu.

Så hur kan jag få min begränsning pålitlig igen?

Exempel 4 – Aktivera begränsningen med WITH CHECK

Om jag vill att min begränsning ska vara betrodd igen måste jag uttryckligen ange WITH CHECK när du återaktiverar den.

Låt oss inaktivera begränsningen igen:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Så nu är jag tillbaka där jag var innan jag återaktiverade det.

Det jag borde ha gjort när jag återaktiverade det var detta:

ALTER TABLE Occupation  
WITH CHECK CHECK CONSTRAINT chkJobTitle; 

Ta nu en ny titt på begränsningen:

SELECT 
  name,
  is_disabled,
  is_not_trusted,
  definition
FROM sys.check_constraints;

Resultat:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Puh! Min begränsning är återigen pålitlig.

Exempel 5 – Aktivera CHECK-begränsningen med ogiltiga data

Naturligtvis är min begränsning bara betrodd igen eftersom jag inte infogade ogiltiga data medan den var inaktiverad. Om jag hade gjort detta skulle jag inte kunna aktivera det med WITH CHECK , som visas nedan.

Om jag inaktiverar det igen:

ALTER TABLE Occupation  
NOCHECK CONSTRAINT chkJobTitle; 

Infoga nu ogiltiga data (och returnera resultaten):

INSERT INTO Occupation
VALUES ( 7, 'Digital Nomad' );

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Resultat:

+----------------+-----------------+
| OccupationId   | JobTitle        |
|----------------+-----------------|
| 1              | Engineer        |
| 2              | Accountant      |
| 3              | Cleaner         |
| 4              | Attorney        |
| 5              | Sales Executive |
| 6              | Uber Driver     |
| 7              | Digital Nomad   |
+----------------+-----------------+

Så vi har infogat ogiltiga data (sista raden).

Detta är ogiltigt eftersom begränsningsdefinitionen ser ut enligt följande:([JobTitle]<>'Digital Nomad')

Det betyder att JobTitle kolumnen får inte innehålla texten Digital Nomad .

Låt oss nu försöka återaktivera CHECK begränsning med WITH CHECK och se vad som händer.

ALTER TABLE Occupation  
WITH CHECK CHECK CONSTRAINT chkJobTitle; 

Resultat:

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'.

Så vi kan inte återaktivera begränsningen med WITH CHECK medan vi har data i tabellen som bryter mot CHECK begränsning. Antingen måste vi uppdatera data eller så måste vi använda WITH NOCHECK (eller helt enkelt utelämna det helt).

Låt oss försöka igen med WITH NOCHECK .

ALTER TABLE Occupation  
WITH NOCHECK CHECK CONSTRAINT chkJobTitle; 

Resultat:

Commands completed successfully.
Total execution time: 00:00:00.015

Så vi kan framgångsrikt aktivera begränsningen om vi inte kontrollerar befintlig data.

Naturligtvis, i det här fallet CHECK begränsningen är fortfarande inte tillförlitlig. Om vi ​​vill att begränsningen ska vara pålitlig måste vi uppdatera informationen så att den inte bryter mot begränsningen.

Exempel:

UPDATE Occupation
SET JobTitle = 'Unemployed'
WHERE OccupationId = 7;

SELECT 
  OccupationId,
  JobTitle
FROM Occupation;

Resultat:

+----------------+-----------------+
| OccupationId   | JobTitle        |
|----------------+-----------------|
| 1              | Engineer        |
| 2              | Accountant      |
| 3              | Cleaner         |
| 4              | Attorney        |
| 5              | Sales Executive |
| 6              | Uber Driver     |
| 7              | Unemployed      |
+----------------+-----------------+

Nu kan vi ändra CHECK begränsning för att bli betrodd igen.

Låt oss göra alla tre tillsammans:

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;

Resultat:

+-----------------+---------------+------------------+----------------------------------------+
| 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')          |
+-----------------+---------------+------------------+----------------------------------------+

Så nu är vår begränsning aktiverad och pålitlig igen, och vår databas är fri från digitala nomader!


  1. Vi introducerar Easysoft Oracle®-drivrutinen i din SOA-miljö

  2. Hur man kontrollerar konfigurationsinställningarna för Databas Mail i SQL Server (T-SQL)

  3. Fel:INSERT EXEC-satsen kan inte kapslas. och Kan inte använda ROLLBACK-satsen i en INSERT-EXEC-sats. Hur löser man detta?

  4. MySql skillnad mellan två tidsstämplar i dagar?