PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Perché posso creare una tabella con PRIMARY KEY su una colonna nullable?

Perché la PRIMARY KEY fa le colonne incluse NOT NULL automaticamente . Cito il manuale qui:

Il vincolo della chiave primaria specifica che una o più colonne di atable possono contenere solo valori univoci (non duplicati) e non nulli. Tecnicamente, PRIMARY KEY è semplicemente una combinazione di UNIQUE e NOT NULL .

Enfasi in grassetto la mia.

Ho eseguito un test per confermare che NOT NULL è completamente ridondante in combinazione con una PRIMARY KEY vincolo (nell'attuale implementazione, ritestato nella versione 13). Il NOT NULL il vincolo rimane anche dopo aver eliminato il vincolo PK, indipendentemente da un esplicito NOT NULL clausola al momento della creazione.

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<>gioca qui

Comportamento identico se NULL è incluso nel CREATE TABLE dichiarazione.

Non farà comunque male mantenere NOT NULL in modo ridondante nei repository di codice se la colonna dovrebbe essere NOT NULL . Se in seguito decidi di modificare il vincolo PK, potresti dimenticare di contrassegnare la colonna NOT NULL - o anche se doveva essere NOT NULL .

C'è un elemento nella wiki di Postgres TODO per disaccoppiare NOT NULL dal vincolo PK. Quindi questo potrebbe cambiare nelle versioni future:

Sposta le informazioni sul vincolo NOT NULL in pg_constraint

Attualmente i vincoli NOT NULL sono memorizzati in pg_attribute senza alcuna designazione delle loro origini, ad es. chiavi primarie. Un problema di manifest è che l'eliminazione di un vincolo PRIMARY KEY non rimuove la designazione del vincolo NOT NULL. Un altro problema è che probabilmente dovremmo forzare la propagazione di NOT NULL dalle tabelle padre ai figli, proprio come lo sono i vincoli CHECK. (Ma allora la caduta della CHIAVE PRIMARIA colpisce i bambini?)

Risposta alla domanda aggiunta

Non sarebbe meglio se questo contraddittorio CREATE TABLE fallisse proprio lì?

Come spiegato sopra, questo

foo_id INTEGER NULL PRIMARY KEY

è (attualmente) equivalente al 100 % a:

foo_id INTEGER PRIMARY KEY

Da NULL viene trattata come una parola non comune in questo contesto.
E non vorremmo che quest'ultimo fallisse. Quindi questa non è un'opzione.