1

I have two colums, foo and bar. foo can only exist with one bar, but can exists n times. If I try to insert foo with a different value of bar, it needs to fail.

 foo | bar
----------
  a  |  a
  a  |  a
  b  |  a
  b  |  a
  b  |  b  <---  this needs to fail.

How can I solve this?

And somewhat tangentially what is the proper language for this question?

1
  • 3
    Perhaps you should normalize your table rather than creating a contraint Commented Jul 24, 2017 at 20:05

1 Answer 1

3

You can use an EXCLUDE constraint.
Using the extension btree_gist:

CREATE EXTENSION btree_gist;

You can define a table

CREATE TABLE fb (
  foo text,
  bar text,
  EXCLUDE USING gist (foo WITH =, bar WITH <>)
);

such that the following insertion is ok:

#= INSERT INTO fb VALUES ('a', 'a'), ('a', 'a'), ('b', 'b');
INSERT 0 3
Time: 1,392 ms
#= SELECT * FROM fb;
┌─────┬─────┐
│ foo │ bar │
├─────┼─────┤
│ a   │ a   │
│ a   │ a   │
│ b   │ b   │
└─────┴─────┘
(3 rows)

but inserting the ('b', 'a') tuple fails because 'b' already has a bar = 'b' row.

#= INSERT INTO fb VALUES ('b', 'a');
ERROR:  23P01: conflicting key value violates exclusion constraint "fb_foo_bar_excl"
DETAIL:  Key (foo, bar)=(b, a) conflicts with existing key (foo, bar)=(b, b).
SCHEMA NAME:  public
TABLE NAME:  fb
CONSTRAINT NAME:  fb_foo_bar_excl

Edit: Though this works I agree with Conrad Frix's comment, normalizing your table is probably a way better idea.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks!! This is a hot fix to the database. I'll probably normalize the database at next code release. Depends greatly on the performance (and priority of course.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.