PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como descobrir se existe restrição de chave exclusiva para determinadas colunas


Você pode consultar os catálogos do sistema para restrições exclusivas , em particular pg_constraint e pg_attribute :
SELECT c.conname, pg_get_constraintdef(c.oid)
FROM   pg_constraint c
JOIN  (
   SELECT array_agg(attnum::int) AS attkey
   FROM   pg_attribute
   WHERE  attrelid = 'tb'::regclass  -- table name optionally schema-qualified
   AND    attname  = ANY('{c1,c2}') 
   ) a ON c.conkey::int[] <@ a.attkey AND c.conkey::int[] @> a.attkey
WHERE  c.contype  = 'u'
AND    c.conrelid = 'tb'::regclass;

  • O tipo de identificador de objeto regclass ajuda a identificar inequivocamente sua tabela.

  • A função de informações do catálogo do sistema pg_get_constraintdef() fornece informações bem formatadas, o que não é estritamente necessário para sua solicitação.

  • Também usando operadores de matriz <@ e @> para garantir que as matrizes correspondam completamente. (A ordem das colunas é desconhecida.) As colunas do sistema são smallint e smallint[] respectivamente. Transmitir para integer para fazê-lo funcionar com esses operadores.

  • Os nomes das colunas diferenciam maiúsculas de minúsculas ao pesquisá-los diretamente no catálogo do sistema. Se você não colocou aspas duplas C1 e C2 no momento da criação, você deve usar c1 e c2 nesse contexto.

  • Também pode haver uma restrição de chave primária de várias colunas reforçando a singularidade. Para cobrir isso na consulta, use:
    WHERE  c.contype IN ('u', 'p')
    

Com base no violino de @Roman, este também demonstra o caso pk:

->SQLfiddle

Índice exclusivo


Ambos os itens acima (restrições exclusivas e pk) são implementados por meio de um índice exclusivo. Além disso, também pode haver índices exclusivos fazendo efetivamente o mesmo que a restrição exclusiva formalmente declarada. Para pegar todos consulte o catálogo do sistema pg_index em vez disso, de forma semelhante:
SELECT c.relname AS idx_name
FROM  (
   SELECT indexrelid, string_to_array(indkey::text, ' ')::int[] AS indkey
   FROM   pg_index
   WHERE  indrelid = 'tb'::regclass
   AND    indisunique                    -- contains "indisprimary"
   ) i
JOIN  (
   SELECT array_agg(attnum::int) AS attkey
   FROM   pg_attribute
   WHERE  attrelid = 'tb'::regclass
   AND    attname  = ANY('{c1,c2}')
   ) a ON i.indkey <@ a.attkey AND i.indkey @> a.attkey
JOIN   pg_class c ON c.oid = i.indexrelid;

A dificuldade especial aqui é o tipo interno int2vector . Eu lido com isso lançando texto e convertendo para int[] .

Esteja ciente de que a implementação de tabelas de catálogo pode mudar entre os principais. É improvável que essas consultas quebrem, mas é possível.