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

Valori NULL per le colonne referential_constraints.unique_constraint_* nello schema delle informazioni

Impostazione di prova

Si assume il nome del vincolo test_def_abc_id_fkey , il nome predefinito risultante dalla tua configurazione in Postgres 11 o versioni precedenti. Vale la pena notare, tuttavia, che i nomi predefiniti sono stati migliorati per Postgres 12, dove la stessa configurazione risulta in test_def_abc_id_abc_id2_fkey . Le note di rilascio per Postgres 12:

Vedi:

db<>violino qui

Quindi usiamo il nome esplicito test_def_abc_fkey per il vincolo FK per evitare confusione:

CREATE TABLE test_abc (
  pk  int PRIMARY KEY
, id  int NOT NULL
, id2 int NOT NULL
);

CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);

CREATE TABLE test_def (
  id      int PRIMARY KEY
, abc_id  int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey  -- !
     FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);

E che funziona in Postgres 9.5 - Postgres 12.
Anche in Postgres 9.3.
(Ho avuto l'impressione sbagliata di un effettivo vincolo sarebbe necessario.)

Risposta

La tua osservazione dall'interrogazione dello schema di informazioni vale:

SELECT *
FROM   information_schema.referential_constraints
WHERE  constraint_name = 'test_def_abc_fkey';  -- unequivocal name

Otteniamo una riga, ma i tre campi unique_constraint_catalog , unique_constraint_schema e unique_constraint_name sono NULL .

La spiegazione sembra semplice. Quelle colonne descrivono, come dice il manuale:

Ma non esiste UNIQUE vincolo , solo un UNIQUE indice . Un UNIQUE il vincolo è implementato usando un UNIQUE indice in Postgres. I vincoli sono definiti dallo standard SQL, gli indici sono dettagli di implementazione. Ci sono differenze come quella che hai scoperto. Correlati:

Lo stesso test con un vero UNIQUE vincolo mostra i dati come previsto:

db<>violino qui

Quindi questo sembra avere senso. Soprattutto perché lo schema informativo è anche definito dal comitato per gli standard SQL e gli indici non sono standardizzati, ma solo vincoli. (Nessuna informazione sull'indice nelle viste dello schema delle informazioni.)

Tutto chiaro? Non proprio.

Comunque

Esiste un'altra visualizzazione dello schema di informazioni key_column_usage . La sua ultima colonna è descritta come:

Grassetto enfasi mia. Qui, la posizione ordinale della colonna nell'indice è comunque elencato:

SELECT *
FROM   information_schema.key_column_usage
WHERE  constraint_name = 'test_def_abc_fkey';

Vedi:

db<>violino qui

Sembra incoerente.

Quel che è peggio, il manuale afferma che una vera e propria PRIMARY KEY o UNIQUE sarebbe richiesto un vincolo per la creazione di una FOREIGN KEY vincolo:

Sembra essere un bug di documentazione ? Se nessuno può indicare dove sbaglio qui, presenterò una segnalazione di bug.

Correlati:

Soluzione

In Postgres, il catalogo di sistema è la vera fonte di verità. Vedi:

Quindi potresti usare qualcosa del genere (come ho anche aggiunto nel violino sopra):

SELECT c.conname
     , c.conrelid::regclass  AS fk_table, k1.fk_columns
     , c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM   pg_catalog.pg_constraint c
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.conrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS fk_columns
   ) k1 ON true
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.confrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS ref_key_columns
   ) k2 ON true
WHERE  conname = 'test_def_abc_fkey';

Resi:

conname           | fk_table | fk_columns       | ref_table | ref_key_columns
:---------------- | :------- | :--------------- | :-------- | :--------------
test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc  | {id,id2}       

Correlati: