Différences entre MATCH FULL, MATCH SIMPLE et MATCH PARTIAL?

29

J'ai remarqué un MATCH SIMPLEet MATCH FULL, mais je ne comprends pas ce qu'ils font. Je vois que la valeur par défaut est MATCH SIMPLE; mais comment fonctionnent les autres MATCHclauses de la FOREIGN KEYcontrainte?

Evan Carroll
la source

Réponses:

38

Consultez la CREATE TABLEpage du manuel :

Il existe trois types de match: MATCH FULL, MATCH PARTIALet MATCH SIMPLE ( ce qui est la valeur par défaut). MATCH FULLne permettra pas qu'une colonne d'une clé étrangère multicolonne soit nulle à moins que toutes les colonnes de clé étrangère soient nulles; s'ils sont tous nuls, la ligne n'a pas besoin d'avoir une correspondance dans la table référencée. MATCH SIMPLEpermet à n'importe quelle colonne de clé étrangère d'être nulle; si l'un d'eux est nul, la ligne n'a pas besoin d'avoir une correspondance dans la table référencée. MATCH PARTIALn'est pas encore implémenté. (Bien sûr, des NOT NULLcontraintes peuvent être appliquées aux colonnes de référence pour empêcher ces cas de se produire.)

Aussi, dans le chapitre sur les clés étrangères :

Normalement, une ligne de référence n'a pas besoin de satisfaire la contrainte de clé étrangère si l'une de ses colonnes de référence est nulle. Si MATCH FULL est ajouté à la déclaration de clé étrangère, une ligne de référence ne s'échappe en satisfaisant à la contrainte que si toutes ses colonnes de référence sont nulles (donc un mélange de valeurs nulles et non nulles garantit l'échec d'une MATCH FULL contrainte). Si vous ne voulez pas que les lignes de référence puissent éviter de satisfaire la contrainte de clé étrangère, déclarez la ou les colonnes de référence comme NOT NULL.

Et assurez-vous de consulter le manuel actuel ou la version correspondant à votre installation. Ne craignez pas les liens Google obsolètes vers des versions obsolètes.

Erwin Brandstetter
la source
7

FULLvs SIMPLEvsPARTIAL

Bien que la réponse choisie soit correcte, si c'est nouveau pour vous, vous voudrez peut-être la voir avec du code - je pense qu'il est plus facile de procéder de cette façon.

-- one row with (1,1)
CREATE TABLE foo ( a int, b int,
  PRIMARY KEY (a,b)
);
INSERT INTO foo (a,b) VALUES (1,1);

--
-- two child tables to reference it
-- 
CREATE TABLE t_full ( a int, b int,
  FOREIGN KEY (a,b) REFERENCES foo MATCH FULL
);
CREATE TABLE t_simple ( a int, b int,
  FOREIGN KEY (a,b) REFERENCES foo MATCH SIMPLE
);

Logiquement, avec FULLet SIMPLE, nous pouvons insérer une correspondance complète.

-- works
INSERT INTO t_full (a,b) VALUES (1,1);
INSERT INTO t_simple (a,b) VALUES (1,1);

Le problème survient lorsque l'une des colonnes l'est NULL.

-- works
INSERT INTO t_simple (a,b) VALUES (1,NULL);

-- fails
INSERT INTO t_full (a,b) VALUES (1,NULL);

L'insertion dans t_fullgénère l'erreur suivante,

ERROR:  insert or update on table "t_full" violates foreign key constraint "t_full_a_fkey"
DETAIL:  MATCH FULL does not allow mixing of null and nonnull key values.
INSERT 0 1

Ok, alors qu'en est-il (42,NULL)- c'est la partie qui m'a toujours dérouté MATCH SIMPLE,

-- works
INSERT INTO t_simple (a,b) VALUES (42,NULL);

Le comportement ci-dessus ne fonctionnerait PAS avec le non implémenté MATCH PARTIAL, qui fait probablement ce que vous voulez pour un index composé où la colonne la plus à droite est NULLsupprimée. Cependant, certaines personnes considèrent cela comme une méthode d'ouverture d'une boîte de Pandore à une mauvaise conception.

Définitions et mnémoniques simples

  • MATCH FULLtout doit correspondre parfaitement , ou toutes les colonnes doivent êtreNULL
  • MATCH SIMPLEsi une chose est NULLla contrainte est simplement ignorée.
  • MATCH PARTIALsi une chose est NULLle fait que tout ne soit pas NULLest partiellement récupéré en faisant quelque chose de sensé dans le but de la contrainte.

Notes de spécification SQL

Pour la postérité, voici les définitions de la spécification SQL sur le <match type>

  • MATCH SIMPLEsi au moins une colonne de référence est nulle, la ligne de la table de référence passe la vérification des contraintes. Si toutes les colonnes de référence ne sont pas nulles, la ligne passe la vérification des contraintes si et seulement s'il existe une ligne de la table référencée qui correspond à toutes les colonnes de référence.
  • MATCH PARTIAL: si toutes les colonnes de référence sont nulles, la ligne de la table de référence passe la vérification des contraintes. Si au moins une colonne de référence n'est pas nulle, la ligne passe la vérification des contraintes si et seulement s'il existe une ligne de la table référencée qui correspond à toutes les colonnes de référence non nulles.
  • MATCH FULL: si toutes les colonnes de référence sont nulles, la ligne de la table de référence passe la vérification des contraintes. Si toutes les colonnes de référence ne sont pas nulles, la ligne passe la vérification des contraintes si et seulement s'il existe une ligne de la table référencée qui correspond à toutes les colonnes de référence. Si une colonne de référence est nulle et une autre colonne de référence n'est pas nulle, la ligne de la table de référence viole la vérification des contraintes.

Bien que cela ne soit pas spécifique à PostgreSQL, ces exemples sont illustrés avec PostgreSQL

Evan Carroll
la source