sql >> Databáze >  >> RDS >> PostgreSQL

Hodnoty NULL pro sloupce reference_constraints.unique_constraint_* v informačním schématu

Testovací nastavení

Předpokládáte název omezení test_def_abc_id_fkey , výchozí název vyplývající z vašeho nastavení v Postgres 11 nebo starším. Za zmínku však stojí, že výchozí názvy byly vylepšeny pro Postgres 12, kde stejné nastavení vede k test_def_abc_id_abc_id2_fkey . Poznámky k vydání Postgres 12:

Viz:

db<>fiddle zde

Použijme tedy explicitní název test_def_abc_fkey pro omezení FK, aby nedošlo k záměně:

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

A že funguje v Postgres 9.5 - Postgres 12.
Dokonce i v Postgresu 9.3.
(Měl jsem mylný dojem, že jde o skutečné omezení bude vyžadováno.)

Odpověď

Vaše pozorování z dotazování na informační schéma platí:

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

Dostaneme řádek, ale tři pole unique_constraint_catalog , unique_constraint_schema a unique_constraint_name jsou NULL .

Vysvětlení se zdá jednoduché. Tyto sloupce popisují, jak to uvádí manuál:

Ale neexistuje žádný UNIQUE omezení , jen UNIQUE index . UNIQUE omezení je implementováno pomocí UNIQUE index v Postgresu. Omezení jsou definována standardem SQL, indexy jsou detaily implementace. Existují rozdíly, jako je ten, který jste objevili. Související:

Stejný test se skutečným UNIQUE omezení zobrazuje data podle očekávání:

db<>fiddle zde

Zdá se tedy, že to dává smysl. Zejména proto, že informační schéma je také definován výborem pro standardy SQL a indexy nejsou standardizovány, pouze omezují. (Žádné indexové informace v zobrazeních informačního schématu.)

Vše jasné? Ne tak docela.

Nicméně

Existuje další zobrazení informačního schématu key_column_usage . Jeho poslední sloupec je popsán jako:

Tučné důraz můj. Zde je pořadová pozice sloupce v indexu je přesto uveden:

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

Viz:

db<>fiddle zde

Zdá se nekonzistentní.

A co je horší, příručka tvrdí, že skutečný PRIMARY KEY nebo UNIQUE omezení by bylo vyžadováno pro vytvoření FOREIGN KEY omezení:

Zdá se, že jde o chybu v dokumentaci ? Pokud zde nikdo nemůže upozornit, kde dělám chybu, podám hlášení o chybě.

Související:

Řešení

V Postgresu je systémový katalog skutečným zdrojem pravdy. Viz:

Takže byste mohli použít něco takového (jako jsem také přidal do housle výše):

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

Vrátí:

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

Související:




  1. PDO bindValue s \PDO::PARAM_BOOL způsobí, že provedení příkazu tiše selže

  2. SQL Dynamic DatePart při použití DateDiff

  3. MySQL vybírá řádky přesně před 7 dny

  4. Nainstalujte Azure Data Studio na Ubuntu 18.04