Hvis du nogensinde kommer i den situation, hvor du skal genaktivere en CHECK
begrænsning, der tidligere er blevet deaktiveret, bør du helt sikkert sikre dig, at du ved, hvad du laver.
Især bør du forstå forskellen mellem WITH NOCHECK
og WITH CHECK
argumenter.
Disse argumenter kan bruges på det tidspunkt, du aktiverer begrænsningen. De angiver, om eksisterende data er valideret mod din genaktiverede (eller nyligt tilføjede) CHECK
begrænsning. Som udgangspunkt har du mulighed for at kontrollere alle eksisterende data for eventuelle overtrædelser af begrænsningen. Hvis du ikke angiver noget, vil eksisterende data ikke blive kontrolleret. Derfor er det vigtigt at forstå, hvordan det fungerer.
Disse argumenter gælder forresten også for fremmednøglebegrænsninger.
Som du måske forventer, WITH CHECK
angiver, at eksisterende data er valideret og WITH NOCHECK
angiver, at det ikke er det. Standardindstillingen er WITH NOCHECK
.
Hvis du bruger WITH NOCHECK
, vil begrænsningen blive markeret som upålidelig. Faktisk er den markeret som upålidelig, når du deaktiverer begrænsningen. Men når du genaktiverer den, vil den forblive upålidelig, medmindre du bruger WITH CHECK
. Med andre ord, hvis du vil gentage dens "troværdighed", skal du udtrykkeligt angive dette.
Med andre ord:
- Når du bruger
WITH NOCHECK
, vil begrænsningen forblive upålidelig. - Når du bruger
WITH CHECK
det vil blive betroet, men kun hvis alle eksisterende data er i overensstemmelse med begrænsningen. Hvis eksisterende data overtræder begrænsningen, vil begrænsningen ikke blive aktiveret, og du vil modtage en fejlmeddelelse.
Når jeg siger "alle eksisterende data", henviser jeg selvfølgelig kun til data, som begrænsningen gælder for.
Der kan være scenarier, hvor du med vilje har deaktiveret en begrænsning, fordi du skulle indtaste data, der overtræder begrænsningen. I sådanne tilfælde, hvis de ugyldige data skal forblive i databasen, skal du bruge WITH NOCHECK
hvis du vil genaktivere begrænsningen. Dette vil give dig mulighed for at aktivere begrænsningen uden at eksisterende data kommer i vejen.
Nedenfor er eksempler, der demonstrerer dette.
Eksempel 1 – Gennemgå begrænsninger for tjek
Lad os først bruge sys.check_constraints
for at tage et kig på alle CHECK
begrænsninger i den aktuelle database.
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, at de alle er aktiveret og har tillid til (fordi de alle har nuller i is_disabled og is_not_trusted kolonner).
For denne artikel vil jeg deaktivere og genaktivere chkJobTitle begrænsning.
Eksempel 2 – Deaktiver begrænsningen
Her deaktiverer jeg chkJobTitle begrænsning:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Færdig.
Lad os nu gennemgå alle begrænsninger 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, at det er blevet deaktiveret (fordi det is_disabled kolonne er indstillet til 1 ).
Du bemærker måske, at
is_not_trusted
kolonne er også indstillet til
1
. Dette indikerer, at CHECK
begrænsning er ikke blevet bekræftet af systemet for alle rækker.
Som nævnt en CHECK
begrænsning kan kun stoles på, hvis alle data har bestået begrænsningens betingelser. Når vi deaktiverer en begrænsning, åbner dette muligheden for, at ugyldige data kommer ind i databasen. Derfor kan vi ikke være 100 % sikre på, at alle data er gyldige, og derfor er begrænsningen markeret som ikke-pålidelig.
Måden at sikre, at begrænsningen er tillid til igen, er at genaktivere den ved hjælp af WITH CHECK
argument. Dette vil få begrænsningen til at kontrollere alle data, før den genaktiveres. Hvis nogen data er ugyldige, vil de ikke kunne genaktiveres. Du skal enten opdatere dataene, så de er gyldige, eller genaktivere begrænsningen ved hjælp af WITH NOCHECK
argument i stedet (hvilket vil få begrænsningen til at forblive upålidelig).
Eksempel 3 – Aktiver begrænsningen ved hjælp af standardindstillingerne (MED NØK)
Lad os genaktivere begrænsningen og køre forespørgslen igen.
For at aktivere begrænsningen vil jeg være doven og bruge standardindstillingerne:
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Bekræft 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å du, hvad der lige skete? Selvom jeg aktiverede begrænsningen igen, er der stadig ingen tillid til den.
Dette skyldes, at jeg var doven (eller måske bare glemsom), da jeg aktiverede begrænsningen. Da jeg aktiverede begrænsningen, glemte jeg at angive WITH CHECK
. Standardindstillingen er WITH NOCHECK
hvilket betyder, at eksisterende data ikke kontrolleres, når begrænsningen genaktiveres.
Det er derfor, du helt sikkert bør vide, hvad du gør, når du aktiverer CHECK
(og FOREIGN KEY
) begrænsninger. Ved at være doven og ikke eksplicit angive en potentielt vigtig indstilling, giver vi SQL Server tilladelse til at vende det blinde øje til eventuelle problemer med eksisterende data.
Men hvis hele grunden til at du skulle deaktivere begrænsningen er at indsætte data, der overtræder begrænsningen, så er standarden WITH NOCHECK
er sandsynligvis, hvad du ønsker.
For nye begrænsninger er standarden WITH CHECK
.
Men i mit tilfælde har jeg ikke indsat eller opdateret nogle data efter deaktivering af begrænsningen, så hvis det var troværdigt før, skulle det stadig være troværdigt nu.
Så hvordan kan jeg få tillid til min begrænsning igen?
Eksempel 4 – Aktiver begrænsningen ved hjælp af MED KONTROL
Hvis jeg vil have tillid til min begrænsning igen, skal jeg udtrykkeligt angive WITH CHECK
når du genaktiverer det.
Lad os deaktivere begrænsningen igen:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Så nu er jeg tilbage til, hvor jeg var, før jeg genaktiverede det.
Hvad jeg skulle have gjort, da jeg genaktiverede det, var dette:
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Tag nu endnu et kig 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') | +-----------------+---------------+------------------+----------------------------------------+
Pyha! Min begrænsning er troværdig igen.
Eksempel 5 – Aktiver CHECK-begrænsningen med ugyldige data
Selvfølgelig er min begrænsning kun tillid til igen, fordi jeg ikke indsatte ugyldige data, mens den var deaktiveret. Hvis jeg havde gjort dette, ville jeg ikke være i stand til at aktivere det ved hjælp af WITH CHECK
, som vist nedenfor.
Hvis jeg deaktiverer det igen:
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Indsæt nu ugyldige data (og returner resultaterne):
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 indsat ugyldige data (sidste række).
Dette er ugyldigt, fordi begrænsningsdefinitionen er som følger:([JobTitle]<>'Digital Nomad')
Det betyder, at
JobTitle
kolonne må ikke indeholde teksten Digital Nomad
.
Lad os nu prøve at genaktivere CHECK
begrænsning ved hjælp af WITH CHECK
og se, hvad der sker.
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 ikke genaktivere begrænsningen ved hjælp af WITH CHECK
mens vi har data i tabellen, der overtræder CHECK
begrænsning. Enten skal vi opdatere dataene, eller også skal vi bruge WITH NOCHECK
(eller bare udelad det helt).
Lad os prøve det igen ved at bruge WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Resultat:
Commands completed successfully. Total execution time: 00:00:00.015
Så vi kan med succes aktivere begrænsningen, hvis vi ikke tjekker de eksisterende data.
Selvfølgelig, i dette tilfælde CHECK
begrænsning er stadig ikke tillid til. Hvis vi vil have tillid til begrænsningen, skal vi opdatere dataene, så de ikke overtræder begrænsningen.
Eksempel:
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 ændre CHECK
begrænsning for at blive betroet igen.
Lad os gøre alle tre sammen:
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 er vores begrænsning aktiveret og troværdig igen, og vores database er fri for digitale nomader!