sql >> Database >  >> RDS >> PostgreSQL

NULL-waarden voor referential_constraints.unique_constraint_* kolommen in informatieschema

Testopstelling

U neemt de beperkingsnaam test_def_abc_id_fkey . aan , de standaardnaam die resulteert uit uw instellingen in Postgres 11 of ouder. Het is echter vermeldenswaard dat de standaardnamen zijn verbeterd voor Postgres 12, waar dezelfde instelling resulteert in test_def_abc_id_abc_id2_fkey . De release-opmerkingen voor Postgres 12:

Zie:

db<>fiddle hier

Laten we dus de expliciete naam test_def_abc_fkey gebruiken voor de FK-beperking om verwarring te voorkomen:

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

En dat werkt in Postgres 9.5 - Postgres 12.
Zelfs in Postgres 9.3.
(Ik had een verkeerde indruk gekregen van een daadwerkelijke beperking zou vereist zijn.)

Antwoord

Uw observatie van het opvragen van het informatieschema houdt in:

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

We krijgen een rij, maar de drie velden unique_constraint_catalog , unique_constraint_schema en unique_constraint_name zijn NULL .

De verklaring lijkt simpel. Die kolommen beschrijven, zoals de handleiding het stelt:

Maar er is geen UNIQUE beperking , gewoon een UNIQUE index . Een UNIQUE beperking wordt geïmplementeerd met behulp van een UNIQUE index in Postgres. Beperkingen worden gedefinieerd door de SQL-standaard, indexen zijn implementatiedetails. Er zijn verschillen zoals degene die je hebt ontdekt. Gerelateerd:

Dezelfde test met een echte UNIQUE beperking toont gegevens zoals verwacht:

db<>fiddle hier

Dit lijkt dus logisch. Vooral omdat het informatieschema wordt ook gedefinieerd door de SQL-standaardcommissie en indexen zijn niet gestandaardiseerd, alleen beperkingen. (Geen indexinformatie in informatieschemaweergaven.)

Alles duidelijk? Niet helemaal.

Echter

Er is nog een informatieschemaweergave key_column_usage . De laatste kolom wordt beschreven als:

Vet nadruk de mijne. Hier de ordinale positie van de kolom in de index wordt toch vermeld:

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

Zie:

db<>fiddle hier

Lijkt onsamenhangend.

Wat erger is, de handleiding beweert dat een werkelijke PRIMARY KEY of UNIQUE beperking zou vereist zijn voor het maken van een FOREIGN KEY beperking:

Lijkt een documentatiefout te zijn ? Als niemand kan aangeven waar ik hier de fout in ga, zal ik een bugrapport indienen.

Gerelateerd:

Oplossing

In Postgres is de systeemcatalogus de eigenlijke bron van waarheid. Zie:

Dus je zou zoiets kunnen gebruiken (zoals ik ook heb toegevoegd in de viool hierboven):

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

Retourneren:

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

Gerelateerd:




  1. MySQL INSERT zonder dat u elk niet-standaardveld hoeft op te geven (#1067 - Ongeldige standaardwaarde voor 'tabel')

  2. Hoe Europese valuta op te slaan in MySQL?

  3. rails COUNT SELECTEER DISTINCT

  4. #1025 - Fout bij hernoemen (errno:150) in mysql