Si jamais vous vous trouvez dans une situation où vous devez réactiver un CHECK
contrainte qui a été précédemment désactivée, vous devez absolument vous assurer que vous savez ce que vous faites.
En particulier, vous devez comprendre la différence entre WITH NOCHECK
et WITH CHECK
arguments.
Ces arguments peuvent être utilisés au moment où vous activez la contrainte. Ils précisent si les données existantes sont validées ou non par rapport à votre CHECK
réactivé (ou nouvellement ajouté) contrainte. Fondamentalement, vous avez la possibilité de vérifier toutes les données existantes pour toute violation de la contrainte. Si vous ne spécifiez rien, les données existantes ne le seront pas être vérifié. C'est pourquoi il est important de comprendre comment cela fonctionne.
Soit dit en passant, ces arguments s'appliquent également aux contraintes de clé étrangère.
Comme vous vous en doutez, WITH CHECK
spécifie que les données existantes sont validées et WITH NOCHECK
précise que non. La valeur par défaut est WITH NOCHECK
.
Si vous utilisez WITH NOCHECK
, la contrainte sera signalée comme non approuvée. En fait, il est signalé comme non approuvé lorsque vous désactivez la contrainte. Mais lorsque vous le réactivez, il restera non fiable à moins que vous n'utilisiez WITH CHECK
. En d'autres termes, si vous souhaitez réaffirmer sa "fiabilité", vous devez le spécifier explicitement.
En d'autres termes :
- Lorsque vous utilisez
WITH NOCHECK
, la contrainte restera non fiable. - Lorsque vous utilisez
WITH CHECK
il deviendra fiable, mais seulement si toutes les données existantes sont conformes à la contrainte. Si des données existantes enfreignent la contrainte, celle-ci ne sera pas activée et vous recevrez un message d'erreur.
Bien entendu, lorsque je dis "toutes les données existantes", je ne fais référence qu'aux données auxquelles la contrainte s'applique.
Il peut y avoir des scénarios dans lesquels vous avez intentionnellement désactivé une contrainte parce que vous avez dû saisir des données qui enfreignent la contrainte. Dans de tels cas, si les données invalides doivent rester dans la base de données, vous devrez utiliser WITH NOCHECK
si vous souhaitez réactiver la contrainte. Cela vous permettra d'activer la contrainte sans qu'aucune donnée existante ne vous gêne.
Vous trouverez ci-dessous des exemples qui le démontrent.
Exemple 1 - Examen des contraintes CHECK
Tout d'abord, utilisons le sys.check_constraints
pour jeter un œil à tous CHECK
contraintes dans la base de données courante.
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Résultat :
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Nous pouvons voir qu'ils sont tous activés et approuvés (car ils ont tous des zéros dans le is_disabled et is_not_trusted colonnes).
Pour cet article, je vais désactiver et réactiver le chkJobTitle contrainte.
Exemple 2 - Désactiver la contrainte
Ici, je désactive le chkJobTitle contrainte :
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Terminé.
Passons maintenant en revue toutes les contraintes :
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Résultat :
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Nous pouvons voir qu'il a été désactivé (parce que son is_disabled la colonne est définie sur 1 ).
Vous remarquerez peut-être que le
is_not_trusted
la colonne est également définie sur
1
. Cela indique que le CHECK
contrainte n'a pas été vérifiée par le système pour toutes les lignes.
Comme mentionné, un CHECK
La contrainte ne peut être approuvée que si toutes les données ont passé avec succès les conditions de la contrainte. Lorsque nous désactivons une contrainte, cela ouvre la possibilité que des données non valides entrent dans la base de données. Par conséquent, nous ne pouvons pas être sûrs à 100 % que toutes les données sont valides, d'où la contrainte signalée comme non fiable.
Le moyen de s'assurer que la contrainte est à nouveau approuvée consiste à la réactiver à l'aide de la commande WITH CHECK
argument. Cela obligera la contrainte à vérifier toutes les données avant de la réactiver. Si des données sont invalides, elles ne pourront pas être réactivées. Vous devrez soit mettre à jour les données pour qu'elles soient valides, soit réactiver la contrainte en utilisant le WITH NOCHECK
argument à la place (ce qui fera que la contrainte restera non fiable).
Exemple 3 - Activer la contrainte à l'aide des paramètres par défaut (WITH NOCHECK)
Réactivons la contrainte et exécutons à nouveau la requête.
Pour activer la contrainte, je vais être paresseux et utiliser les paramètres par défaut :
ALTER TABLE Occupation CHECK CONSTRAINT chkJobTitle;
Vérifiez maintenant la modification :
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Résultat :
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Avez-vous vu ce qui vient de se passer ? Même si j'ai réactivé la contrainte, elle n'est toujours pas fiable.
C'est parce que j'étais paresseux (ou peut-être juste oublieux) quand j'ai activé la contrainte. Lorsque j'ai activé la contrainte, j'ai oublié de spécifier WITH CHECK
. La valeur par défaut est WITH NOCHECK
ce qui signifie que les données existantes ne sont pas vérifiées lors de la réactivation de la contrainte.
C'est pourquoi vous devez absolument savoir ce que vous faites lorsque vous activez CHECK
(et FOREIGN KEY
) contraintes. En étant paresseux et en ne spécifiant pas explicitement un paramètre potentiellement important, nous donnons à SQL Server la permission de fermer les yeux sur tout problème avec les données existantes.
Cependant, si la seule raison pour laquelle vous deviez désactiver la contrainte est d'insérer des données qui violent la contrainte, alors la valeur par défaut WITH NOCHECK
est probablement ce que vous voulez.
Au fait, pour les nouvelles contraintes, la valeur par défaut est WITH CHECK
.
Mais dans mon cas, je n'ai inséré ou mis à jour aucune données après avoir désactivé la contrainte, donc si elles étaient fiables auparavant, elles devraient toujours l'être maintenant.
Alors, comment puis-je redonner confiance à ma contrainte ?
Exemple 4 - Activer la contrainte à l'aide de WITH CHECK
Si je veux que ma contrainte soit à nouveau approuvée, je dois spécifier explicitement WITH CHECK
lors de sa réactivation.
Désactivons à nouveau la contrainte :
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Alors maintenant, je suis de retour là où j'étais avant de le réactiver.
Voici ce que j'aurais dû faire lorsque je l'ai réactivé :
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Maintenant, regardez à nouveau la contrainte :
SELECT name, is_disabled, is_not_trusted, definition FROM sys.check_constraints;
Résultat :
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Phew! Ma contrainte redevient digne de confiance.
Exemple 5 - Activer la contrainte CHECK avec des données non valides
Bien sûr, ma contrainte n'est à nouveau approuvée que parce que je n'ai pas inséré de données invalides alors qu'elle était désactivée. Si j'avais fait cela, je n'aurais pas pu l'activer en utilisant WITH CHECK
, comme illustré ci-dessous.
Si je le désactive à nouveau :
ALTER TABLE Occupation NOCHECK CONSTRAINT chkJobTitle;
Insérez maintenant des données invalides (et renvoyez les résultats) :
INSERT INTO Occupation VALUES ( 7, 'Digital Nomad' ); SELECT OccupationId, JobTitle FROM Occupation;
Résultat :
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Digital Nomad | +----------------+-----------------+
Nous avons donc réussi à insérer des données invalides (dernière ligne).
Ceci n'est pas valide car la définition de la contrainte est la suivante :([JobTitle]<>'Digital Nomad')
Cela signifie que le
JobTitle
la colonne ne doit pas contenir le texte Digital Nomad
.
Essayons maintenant de réactiver le CHECK
contrainte utilisant WITH CHECK
et voyez ce qui se passe.
ALTER TABLE Occupation WITH CHECK CHECK CONSTRAINT chkJobTitle;
Résultat :
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'.
Nous ne pouvons donc pas réactiver la contrainte en utilisant WITH CHECK
alors que nous avons des données dans la table qui violent le CHECK
contrainte. Soit nous devons mettre à jour les données, soit nous devons utiliser WITH NOCHECK
(ou simplement omettez-le complètement).
Essayons à nouveau en utilisant WITH NOCHECK
.
ALTER TABLE Occupation WITH NOCHECK CHECK CONSTRAINT chkJobTitle;
Résultat :
Commands completed successfully. Total execution time: 00:00:00.015
Nous pouvons donc activer la contrainte avec succès si nous ne vérifions pas les données existantes.
Bien entendu, dans ce cas le CHECK
la contrainte n'est toujours pas fiable. Si nous voulons que la contrainte soit fiable, nous devrons mettre à jour les données afin qu'elles ne violent pas la contrainte.
Exemple :
UPDATE Occupation SET JobTitle = 'Unemployed' WHERE OccupationId = 7; SELECT OccupationId, JobTitle FROM Occupation;
Résultat :
+----------------+-----------------+ | OccupationId | JobTitle | |----------------+-----------------| | 1 | Engineer | | 2 | Accountant | | 3 | Cleaner | | 4 | Attorney | | 5 | Sales Executive | | 6 | Uber Driver | | 7 | Unemployed | +----------------+-----------------+
Maintenant, nous pouvons modifier le CHECK
contrainte de redevenir digne de confiance.
Faisons les trois ensemble :
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;
Résultat :
+-----------------+---------------+------------------+----------------------------------------+ | 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') | +-----------------+---------------+------------------+----------------------------------------+
Alors maintenant, notre contrainte est à nouveau activée et digne de confiance, et notre base de données est exempte de nomades numériques !