Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find whether unique key constraint exists for given columns

I am working on a perl script, where i need to run update queries. But I need to check if the update sql command does not violate unique key constraint. So if I have a table tb(C1,C2,C3) and my update query is like:

update tb set C1='b1' where C2='a1' ;

Is there a way to find if a unique key constraint exist for column C1,C2 before trying to update? Ie: UNIQUE(C1,C2).

like image 799
Anant Avatar asked Nov 20 '13 04:11

Anant


People also ask

What is unique constraint in SQL?

SQL UNIQUE Constraint. The UNIQUE constraint ensures that all values in a column are different. Both the UNIQUE and PRIMARY KEY constraints provide a guarantee for uniqueness for a column or set of columns. A PRIMARY KEY constraint automatically has a UNIQUE constraint.

How do I add a unique key constraint to a column?

–Adding unique key constraint to a column. ADD CONSTRAINT <identifier_name> UNIQUE (<column_name1>, <column_name2>,…); ALTER TABLE demo ADD UNIQUE (PHONE); --Let's insert a row into the table.

How many unique and primary key constraints can I have?

However, you can have many UNIQUE constraints per table, but only one PRIMARY KEY constraint per table. The following SQL creates a UNIQUE constraint on the "ID" column when the "Persons" table is created:

How can I see if a column has a constraint?

set the owner, table and column of interest and it will show you all constraints that cover that column Note that this won't show all cases where a unique index exists on a column (as its possible to have a unique index in place without a constraint being present).


2 Answers

You can query the system catalogs for unique constraints, in particular pg_constraint and 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;
  • The object identifer type regclass helps to unambiguously identify your table.

  • The system catalog information function pg_get_constraintdef() gets you nicely formatted information, which is not strictly necessary for your request.

  • Also using array operators <@ and @> to make sure the arrays match completely. (The order of columns is unknown.) The system columns are smallint and smallint[] respectively. Cast to integer to make it work with those operators.

  • Column names are case sensitive when looking them up in the system catalog directly. If you didn't double-quote C1 and C2 at creation time, you have to use c1 and c2 in this context.

  • There could also be a multicolumn primary key constraint enforcing uniqueness. To cover that in the query use instead:

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

Building on @Roman's fiddle, this one also demonstrates the pk case:

->SQLfiddle

Unique index

Both of the above (unique & pk constraints) are implemented by way of a unique index. In addition there can also be unique indices doing effectively the same as formally declared unique constraint. To catch all of them query the system catalog pg_index instead, in a similar fashion:

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;

Special difficulty here is the internal type int2vector. I deal with it by casting text and converting to int[].

Be aware that implementation of catalog tables might change across major. Unlikely that these queries break, but possible.

like image 126
Erwin Brandstetter Avatar answered Oct 13 '22 21:10

Erwin Brandstetter


You can find out whether a constraint exists (non-portably) by inspecting the pg_catalog.pg_constraint table, but that won't tell you whether the constraint would be violated by your insert, and it would be prone to races even if it could.

The correct thing to do is to try the insert and handle a failure appropriately.

like image 25
hobbs Avatar answered Oct 13 '22 21:10

hobbs