Parce que la PRIMARY KEY fait la ou les colonnes incluses NOT NULL automatiquement . Je cite le manuel ici :
La contrainte de clé primaire spécifie qu'une ou plusieurs colonnes d'une table ne peuvent contenir que des valeurs uniques (non dupliquées) et non nulles. Techniquement,
PRIMARY KEYest simplement une combinaison deUNIQUEetNOT NULL.
J'insiste sur moi.
J'ai exécuté un test pour confirmer que NOT NULL est complètement redondant en combinaison avec une PRIMARY KEY contrainte (dans l'implémentation actuelle, retestée en version 13). Le NOT NULL la contrainte reste même après avoir supprimé la contrainte PK, indépendamment d'un NOT NULL explicite clause au moment de la création.
CREATE TABLE foo (foo_id int PRIMARY KEY);
ALTER TABLE foo DROP CONSTRAINT foo_pkey;
db=# \d foo
table »public.foo«
column | type | attribute
--------+---------+-----------
foo_id | integer | not null -- stays
db<>jouez ici
Comportement identique si NULL est inclus dans le CREATE TABLE déclaration.
Cela ne fera toujours pas de mal de garder NOT NULL de manière redondante dans les référentiels de code si la colonne est censée être NOT NULL . Si vous décidez ultérieurement de modifier la contrainte PK, vous risquez d'oublier de marquer la colonne NOT NULL - ou s'il était même censé être NOT NULL .
Il y a un élément dans le wiki Postgres TODO pour découpler NOT NULL de la contrainte PK. Cela pourrait donc changer dans les futures versions :
Déplacer les informations de contrainte NOT NULL vers pg_constraint
Actuellement, les contraintes NOT NULL sont stockées dans pg_attribute sans aucune désignation de leurs origines, par ex. clés primaires. Un problème manifeste est que la suppression d'une contrainte PRIMARY KEY ne supprime pas la désignation de contrainte NOT NULL. Un autre problème est que nous devrions probablement forcer la propagation de NOT NULL des tables parents aux enfants, tout comme le sont les contraintes CHECK. (Mais est-ce que laisser tomber PRIMARY KEY affecte les enfants ?)
Réponse à la question ajoutée
Ne serait-il pas préférable que ce CREATE TABLE contradictoire échoue juste là ?
Comme expliqué ci-dessus, cela
foo_id INTEGER NULL PRIMARY KEY
est (actuellement) 100 % équivalent à :
foo_id INTEGER PRIMARY KEY
Depuis NULL est traité comme un mot parasite dans ce contexte.
Et nous ne voudrions pas que ce dernier échoue. Ce n'est donc pas une option.