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