PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment savoir si une contrainte de clé unique existe pour des colonnes données

Vous pouvez interroger les catalogues système pour les contraintes uniques , en particulier pg_constraint et 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;
  • Le type d'identifiant d'objet regclass aide à identifier sans ambiguïté votre table.

  • La fonction d'informations sur le catalogue système pg_get_constraintdef() vous obtient des informations bien formatées, qui ne sont pas strictement nécessaires pour votre demande.

  • Utilise également les opérateurs de tableau <@ et @> pour vous assurer que les tableaux correspondent complètement. (L'ordre des colonnes est inconnu.) Les colonnes système sont smallint et smallint[] respectivement. Convertir en integer pour le faire fonctionner avec ces opérateurs.

  • Les noms de colonne sont sensibles à la casse lorsque vous les recherchez directement dans le catalogue système. Si vous n'avez pas mis entre guillemets C1 et C2 au moment de la création, vous devez utiliser c1 et c2 dans ce contexte.

  • Il peut également y avoir une contrainte de clé primaire multicolonne imposer l'unicité. Pour couvrir cela dans la requête, utilisez à la place :

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

S'appuyant sur le violon de @Roman, celui-ci illustre également le cas pk :

->SQLfiddle

Indice unique

Les deux contraintes ci-dessus (contraintes uniques et pk) sont implémentées au moyen d'un index unique. De plus, il peut également y avoir des indices uniques faire effectivement la même chose que la contrainte unique formellement déclarée. Pour les attraper tous interroger le catalogue système pg_index à la place, de la même manière :

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 difficulté particulière ici est le type interne int2vector . Je m'en occupe en diffusant du texte et en le convertissant en int[] .

Sachez que l'implémentation des tables de catalogue peut changer d'un domaine à l'autre. Il est peu probable que ces requêtes échouent, mais c'est possible.