Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Ce que vous devez savoir sur WITH NOCHECK lors de l'activation d'une contrainte CHECK dans SQL Server

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 !