Puoi interrogare i cataloghi di sistema
per vincoli unici , in particolare 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;
-
Il tipo di identificatore di oggetto
regclass
aiuta a identificare inequivocabilmente la tua tabella. -
La funzione di informazioni del catalogo di sistema
pg_get_constraintdef()
ti fornisce informazioni ben formattate, che non sono strettamente necessarie per la tua richiesta. -
Usando anche operatori di array
<@
e@>
per assicurarsi che gli array corrispondano completamente. (L'ordine delle colonne è sconosciuto.) Le colonne di sistema sonosmallint
esmallint[]
rispettivamente. Trasmetti ainteger
per farlo funzionare con quegli operatori. -
I nomi delle colonne fanno distinzione tra maiuscole e minuscole quando vengono cercati direttamente nel catalogo di sistema. Se non hai tra virgolette
C1
eC2
al momento della creazione, devi usarec1
ec2
in questo contesto. -
Potrebbe esserci anche un vincolo chiave primaria multicolonna imporre l'unicità. Per coprirlo nella query usa invece:
WHERE c.contype IN ('u', 'p')
Basandosi sul violino di @Roman, questo dimostra anche il caso pk:
Indice unico
Entrambi i precedenti (vincoli univoci e pk) sono implementati tramite un indice univoco. Inoltre possono esserci anche indici unici facendo effettivamente la stessa cosa del vincolo unico formalmente dichiarato. Per catturarli tutti interrogare il catalogo di sistema pg_index
invece, in modo simile:
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;
Difficoltà speciale qui è il tipo interno int2vector
. Mi occupo di trasmettere il testo e di convertirlo in int[]
.
Tieni presente che l'implementazione delle tabelle del catalogo potrebbe cambiare tra le principali. È improbabile che queste query si interrompano, ma possibile.