Configuração do teste
Você assume o nome da restrição
test_def_abc_id_fkey
, o nome padrão resultante de sua configuração no Postgres 11 ou anterior. Vale a pena notar, porém, que os nomes padrão foram aprimorados para o Postgres 12, onde a mesma configuração resulta em test_def_abc_id_abc_id2_fkey
. As notas de lançamento do Postgres 12: Ver:
db<>fiddle aqui
Então vamos usar o nome explícito
test_def_abc_fkey
para a restrição FK para evitar confusão: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 isso funciona no Postgres 9.5 - Postgres 12.
Mesmo no Postgres 9.3.
(Eu estava com a impressão errada de uma restrição real seria necessário.)
Resposta
Sua observação ao consultar o esquema de informações é válida:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
Obtemos uma linha, mas os três campos
unique_constraint_catalog
, unique_constraint_schema
e unique_constraint_name
são NULL
. A explicação parece simples. Essas colunas descrevem, como o manual coloca:
Mas não há
UNIQUE restrição
, apenas um UNIQUE
índice
. Um ÚNICO
restrição é implementada usando um UNIQUE
índice no Postgres. As restrições são definidas pelo padrão SQL, os índices são detalhes de implementação. Existem diferenças como a que você descobriu. Relacionado:O mesmo teste com um
UNIQUE
real restrição mostra os dados como esperado:db<>fiddle aqui
Então isso parece fazer sentido. Especialmente porque o esquema de informações também é definido pelo comitê de padrões SQL e os índices não são padronizados, apenas restrições. (Nenhuma informação de índice nas visualizações do esquema de informações.)
Tudo limpo? Não exatamente.
No entanto
Há outra visualização de esquema de informações
key_column_usage
. Sua última coluna é descrita como:Negrito ênfase minha. Aqui, a posição ordinal da coluna no índice está listado de qualquer maneira:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
Ver:
db<>fiddle aqui
Parece inconsistente.
O que é pior, o manual afirma que uma
CHAVE PRIMÁRIA
real ou ÚNICO
restrição seria necessária para a criação de uma FOREIGN KEY
restrição:Parece ser um bug de documentação ? Se ninguém puder apontar onde estou errando aqui, apresentarei um relatório de bug.
Relacionado:
Solução
No Postgres, o catálogo do sistema é a verdadeira fonte da verdade. Ver:
Então você pode usar algo assim (como eu também adicionei no fiddle acima de):
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';
Devoluções:
conname | fk_table | fk_columns | ref_table | ref_key_columns :---------------- | :------- | :--------------- | :-------- | :-------------- test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Relacionado:
- Encontre o nome da tabela referenciada usando o nome da tabela, do campo e do esquema
- Encontrar campo referenciado( s) de restrição de chave estrangeira
- Como posso encontrar tabelas que fazem referência a uma linha específica por meio de uma chave estrangeira?