Reputation: 1222
I'm curious if there is a way to write a unique constraint to support the following situation.
Suppose I have table table1
with facts about a user, with four columns:
user_id
: unique id for usersource
: where the detail came fromd1
: dimension 1 of the factd2
: dimension 2 of the factThe following is an example of data in this table:
| row_id | user_id | source | d1 | d2 |
|--------|---------|--------|--------|---------|
| 1 | aaa111 | foo | bar | 123 |
| 2 | aaa111 | foo | baz | 'horse' |
| 3 | aaa111 | scrog | bar | 123 |
| 4 | bbb222 | foo | goober | 456 |
Currently, a unique constraint exists on source + d1 + d2
. This is good, because it allows the same user to have duplicates of (d1,d2)
, as long as they have a different source
.
Rows #1 and #3 demonstrate this for user aaa111
.
However, this constraint does not prevent the following row from getting added...
| row_id | user_id | source | d1 | d2 |
|--------|---------|--------|--------|---------|
| 1 | aaa111 | foo | bar | 123 |
| 2 | aaa111 | foo | baz | 'horse' |
| 3 | aaa111 | scrog | bar | 123 |
| 4 | bbb222 | foo | goober | 456 |
| 5 | bbb222 | turnip | baz | 'horse' | <---- allowed new row
...because source
is different for rows #2 and #5.
I would like to add a unique constraint where the combination of (d1,d2)
may only exist for a single user_id
.
Said another way, a single user can have as many unique (source, d1, d2)
combinations as needed, but cannot share (d1,d2)
with another user_id
.
Is this data model fundamentally flawed to support this constraint? or is there a unique constraint that might help enforce this? Thanks in advance for any suggestions.
Upvotes: 0
Views: 148
Reputation: 3349
It's a conditional-constraint, you can use a trigger BEFORE INSERT OR UPDATE that raise exception when violate the constraint:
CREATE OR REPLACE FUNCTION check_user_combination() RETURNS trigger AS
$$
DECLARE
vCheckUser INTEGER;
BEGIN
SELECT INTO vCheckUser user_id
FROM table1
WHERE d1 = NEW.d1
AND d2 = NEW.d2
AND user_id <> NEW.user_id;
IF vCheckUser IS NOT NULL THEN
RAISE EXCEPTION 'User % have already d1=% and d2=%',vCheckUser,NEW.d1, NEW.d2;
END IF;
RETURN NEW;
END;
$$
language 'plpgsql';
CREATE TRIGGER tr_check_combination BEFORE INSERT OR UPDATE ON table1 FOR EACH ROW EXECUTE PROCEDURE check_user_combination();
This prevent insert or update additional user for the same d1 and d2.
Upvotes: 1