sql >> Base de Datos >  >> RDS >> PostgreSQL

Cómo encontrar si existe una restricción de clave única para columnas dadas

Puede consultar los catálogos del sistema para restricciones únicas , en particular pg_constraint y 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;
  • El tipo de identificador de objeto regclass ayuda a identificar sin ambigüedades su tabla.

  • La función de información del catálogo del sistema pg_get_constraintdef() obtiene información con un buen formato, que no es estrictamente necesaria para su solicitud.

  • También usando operadores de matriz <@ y @> para asegurarse de que las matrices coincidan completamente. (Se desconoce el orden de las columnas). Las columnas del sistema son smallint y smallint[] respectivamente. Convertir a integer para que funcione con esos operadores.

  • Los nombres de las columnas distinguen entre mayúsculas y minúsculas cuando se buscan directamente en el catálogo del sistema. Si no entrecomillas dobles C1 y C2 en el momento de la creación, debe usar c1 y c2 en este contexto.

  • También podría haber una restricción de clave principal de varias columnas imponer la unicidad. Para cubrir eso en la consulta, use en su lugar:

    WHERE  c.contype IN ('u', 'p')
    

Basado en el violín de @Roman, este también demuestra el caso pk:

->SQLfiddle

Índice único

Ambos de los anteriores (restricciones únicas y de pk) se implementan mediante un índice único. Además también puede haber índices únicos haciendo efectivamente lo mismo que la restricción única declarada formalmente. Para atraparlos a todos consultar el catálogo del sistema pg_index en cambio, de manera similar:

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;

La dificultad especial aquí es el tipo interno int2vector . Lo trato enviando texto y convirtiéndolo a int[] .

Tenga en cuenta que la implementación de las tablas de catálogo puede cambiar entre las principales. Es poco probable que estas consultas se rompan, pero es posible.