PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

NULL-Werte für referential_constraints.unique_constraint_*-Spalten im Informationsschema

Testaufbau

Sie nehmen den Constraint-Namen test_def_abc_id_fkey an , der Standardname, der sich aus Ihrer Einrichtung in Postgres 11 oder älter ergibt. Erwähnenswert ist jedoch, dass die Standardnamen für Postgres 12 verbessert wurden, wo dieselbe Einrichtung zu test_def_abc_id_abc_id2_fkey führt . Die Versionshinweise für Postgres 12:

Siehe:

db<>fiddle hier

Verwenden wir also den expliziten Namen test_def_abc_fkey für die FK-Einschränkung, um Verwirrung zu vermeiden:

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)
);

Und das funktioniert in Postgres 9.5 - Postgres 12.
Sogar in Postgres 9.3.
(Ich hatte den falschen Eindruck einer tatsächlichen Einschränkung erforderlich.)

Antwort

Ihre Beobachtung aus der Abfrage des Informationsschemas gilt:

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

Wir erhalten eine Zeile, aber die drei Felder unique_constraint_catalog , unique_constraint_schema und unique_constraint_name sind NULL .

Die Erklärung scheint einfach. Diese Spalten beschreiben, wie es im Handbuch heißt:

Aber es gibt keinen UNIQUE Einschränkung , nur ein UNIQUE Index . Ein UNIQUE Einschränkung wird mit einem UNIQUE implementiert Index in Postgres. Einschränkungen werden vom SQL-Standard definiert, Indizes sind Implementierungsdetails. Es gibt Unterschiede wie den, den Sie entdeckt haben. Verwandte:

Derselbe Test mit einem tatsächlichen UNIQUE Einschränkung zeigt Daten wie erwartet:

db<>fiddle hier

Das scheint also Sinn zu machen. Vor allem seit dem Informationsschema wird auch vom SQL Standards Committee definiert und Indizes sind nicht standardisiert, sondern nur Einschränkungen. (Keine Indexinformationen in Informationsschemaansichten.)

Alles klar? Nicht ganz.

Allerdings

Es gibt eine weitere Ansicht des Informationsschemas key_column_usage . Seine letzte Spalte wird wie folgt beschrieben:

Fett Betonung von mir. Hier die Ordinalposition der Spalte im Index wird trotzdem aufgelistet:

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

Siehe:

db<>fiddle hier

Scheint widersprüchlich.

Was noch schlimmer ist, das Handbuch behauptet, dass ein tatsächlicher PRIMARY KEY oder UNIQUE Einschränkung wäre für die Erstellung eines FOREIGN KEY erforderlich Einschränkung:

Scheint ein Dokumentationsfehler zu sein ? Wenn niemand darauf hinweisen kann, wo ich hier falsch liege, werde ich einen Fehlerbericht einreichen.

Verwandte:

Lösung

In Postgres ist der Systemkatalog die eigentliche Quelle der Wahrheit. Siehe:

Sie könnten also so etwas verwenden (wie ich es auch in der Fiddle hinzugefügt habe oben):

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';

Rückgabe:

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

Verwandte: