Qu'est-ce qu'une CONTRAINTE AVEC CHECK CHECK?

18

J'ai du T-SQL généré automatiquement, qui est probablement valide, mais je ne comprends pas vraiment.

ALTER TABLE [dbo].[MyTable]
WITH CHECK
CHECK CONSTRAINT [My_FORIEGN_KEY];

Je sais ce qu'est une contrainte de clé étrangère, mais quel est le problème CHECK CHECK?

BanksySan
la source

Réponses:

27

La page de documentation de MSDN sur ALTER TABLEexplique ces éléments:

  • ALTER TABLE: modifier la structure de la table
    (et certaines des actions / modifications possibles sont):
    • CHECK CONSTRAINT ..: activer la contrainte
    • NOCHECK CONSTRAINT ..: désactiver la contrainte
      Il existe également des étapes supplémentaires facultatives à effectuer lors de la création / activation / désactivation d'une contrainte:
      • WITH CHECK: vérifiez également la contrainte
      • WITH NOCHECK: ne pas vérifier la contrainte

Dans leurs mots:

| [ WITH { CHECK | NOCHECK } ] { CHECK | NOCHECK } CONSTRAINT   
    { ALL | constraint_name [ ,...n ] }

...

WITH CHECK | WITH NOCHECK Spécifie si les données de la table sont ou non validées par rapport à une contrainte FOREIGN KEYou une CHECKcontrainte nouvellement ajoutée ou réactivée . S'il n'est pas spécifié, WITH CHECKest supposé pour les nouvelles contraintes et WITH NOCHECKest supposé pour les contraintes réactivées.

Si vous ne souhaitez pas vérifier les nouvelles CHECKou les FOREIGN KEYcontraintes par rapport aux données existantes, utilisez WITH NOCHECK. Nous vous déconseillons de le faire, sauf dans de rares cas. La nouvelle contrainte sera évaluée dans toutes les mises à jour de données ultérieures. Toute violation de contrainte supprimée par WITH NOCHECKl'ajout de la contrainte peut entraîner l'échec des mises à jour futures si elles mettent à jour les lignes avec des données non conformes à la contrainte.

L'optimiseur de requêtes ne prend pas en compte les contraintes définies WITH NOCHECK. Ces contraintes sont ignorées jusqu'à ce qu'elles soient réactivées à l'aide de ALTER TABLEtable WITH CHECK CHECK CONSTRAINT ALL.

...

{ CHECK | NOCHECK } CONSTRAINT
Spécifie que nom_contrainte est activé ou désactivé. Cette option ne peut être utilisée qu'avec FOREIGN KEYet CHECKcontraintes. Lorsque NOCHECKest spécifié, la contrainte est désactivée et les insertions ou mises à jour futures de la colonne ne sont pas validées par rapport aux conditions de contrainte. DEFAULT, PRIMARY KEYet les UNIQUEcontraintes ne peuvent pas être désactivées.

Test dans dbfiddle :

CREATE TABLE a (aid INT PRIMARY KEY);

ALLER

INSERT INTO a (aid)
VALUES (1), (2), (3) ;

ALLER

3 lignes affectées
CREATE TABLE b 
( aid INT,
  bid INT PRIMARY KEY,
  CONSTRAINT [My_FORIEGN_KEY]
    FOREIGN KEY (aid) REFERENCES a (aid)
) ;

ALLER

INSERT INTO b (aid, bid)
VALUES
  (1, 11),
  (1, 12),
  (2, 21), 
  (3, 31) ;

ALLER

4 lignes affectées
INSERT INTO b (aid, bid)
VALUES
  (6, 61),
  (6, 62) ;

ALLER

Msg 547 Niveau 16 State 0 Line 1
L'instruction INSERT était en conflit avec la contrainte FOREIGN KEY "My_FORIEGN_KEY". Le conflit s'est produit dans la base de données "fiddle_792fce5de09f42908c3a0f91421f3522", table "dbo.a", colonne "aide".
Msg 3621 niveau 0 état 0 ligne 1
La déclaration est terminée.
SELECT * FROM b ;

ALLER

aide | offre
-: | -:
  1 | 11
  1 | 12
  2 | 21
  3 | 31
ALTER TABLE b NOCHECK CONSTRAINT [My_FORIEGN_KEY];   --disable

ALLER

INSERT INTO b (aid, bid)
VALUES
  (4, 41),
  (4, 42) ;

ALLER

2 lignes affectées
SELECT * FROM b ;

ALLER

aide | offre
-: | -:
  1 | 11
  1 | 12
  2 | 21
  3 | 31
  4 | 41
  4 | 42
ALTER TABLE b WITH NOCHECK CHECK CONSTRAINT [My_FORIEGN_KEY];  
-- enable constraint without checking existing data

ALLER

SELECT * FROM b ;

ALLER

aide | offre
-: | -:
  1 | 11
  1 | 12
  2 | 21
  3 | 31
  4 | 41
  4 | 42
INSERT INTO b (aid, bid)
VALUES
  (6, 61),
  (6, 62) ;

ALLER

Msg 547 Niveau 16 State 0 Line 1
L'instruction INSERT était en conflit avec la contrainte FOREIGN KEY "My_FORIEGN_KEY". Le conflit s'est produit dans la base de données "fiddle_792fce5de09f42908c3a0f91421f3522", table "dbo.a", colonne "aide".
Msg 3621 niveau 0 état 0 ligne 1
La déclaration est terminée.
SELECT * FROM b ;

ALLER

aide | offre
-: | -:
  1 | 11
  1 | 12
  2 | 21
  3 | 31
  4 | 41
  4 | 42
ALTER TABLE b WITH CHECK CHECK CONSTRAINT [My_FORIEGN_KEY];  
-- check existing data and enable constraint 

ALLER

Msg 547 Niveau 16 State 0 Line 1
L'instruction ALTER TABLE était en conflit avec la contrainte FOREIGN KEY "My_FORIEGN_KEY". Le conflit s'est produit dans la base de données "fiddle_792fce5de09f42908c3a0f91421f3522", table "dbo.a", colonne "aide".
ypercubeᵀᴹ
la source
1
Merci. Wrt ALTER TABLE b WITH NOCHECK CHECK CONSTRAINT [My_FORIEGN_KEY]; -- enable constraint without checking, cela signifie-t-il que la contrainte ne vérifiera pas les données existantes, seulement les nouvelles données entrantes?
BanksySan
1
Exactement. Voyez comment l'insertion suivante (aide = 6) n'est pas autorisée mais les lignes existantes (avec aide = 4) sont toujours là.
ypercubeᵀᴹ
Cela le démontre parfaitement.
BanksySan
1

Pensez à lire l'article ici: https://msdn.microsoft.com/en-us/library/ms190273.aspx

Il nous dit: «L'optimiseur de requêtes ne prend pas en compte les contraintes définies AVEC NOCHECK. Ces contraintes sont ignorées jusqu'à ce qu'elles soient réactivées à l'aide de la table ALTER TABLE AVEC CHECK CHECK CONSTRAINT ALL '

Considérez également ce fil sur StackOverflow: /programming/529941/with-check-add-constraint-followed-by-check-constraint-vs-add-constraint

George K
la source