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!