Skip to content
Advertisement

Postgresql: Unique constraint over Union of 2 columns

I have the following tables:

TRANSACTIONS

 id   |   amount
------------------
  1   |    100
  2   |    -100
  3   |    250
  4   |   -250

TRANSACTION_LINKS

id  | send_tx  | receive_tx
---------------------------
 1  |     2    |     1 
 2  |     4    |     2 

The send_tx and receive_tx columns in the transaction links table use foreign keys pointing to the ID of the transactions table.

This is how I create the transaction links table

CREATE TABLE IF NOT EXISTS transaction_links
(
    id            BIGSERIAL PRIMARY KEY,
    send_id       INT NOT NULL UNIQUE REFERENCES transactions(id) ON DELETE
    RESTRICT,
    receive_id    INT NOT NULL UNIQUE REFERENCES transactions(id) ON DELETE
    RESTRICT
);

I want to create a unique constraint over both send_tx and receive_tx, meaning that if transaction id 1 is found in the receive_tx column, then

  • no other transaction link can have the receiving_tx = 1
  • no other transaction link can have the sending_tx = 1

I know that I can have a unique constraint on each column separately, but that only solves my first problem

EDIT:

essentially, if I insert (1,2) into transaction links, then inserting (1,3) or (3,1) or (4,2) or (2,4) should all be rejected Also, in my design, the transactions table contains many more columns than what is shown here, I’ve only included the amount for simplicity’s sake.

Advertisement

Answer

You can use an exclusion constraint which only requires a single index:

alter table transaction_links
  add constraint check_tx
  exclude using gist ( (array[send_id, receive_id]) with &&);

The && operator is the “overlaps” operator for arrays – which means “have elements in common, regardless of the order of the elements in the array. In this case the constraint prevents to insert any row where any value of (send_id, receive_id) appears in some other row of the table (regardless of the column).

However, you need the intarray extension for that.

Online example: https://rextester.com/QOYS23482

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement