patternsqlMinor
Uniqueness constraint in union of two columns' values
Viewed 0 times
columnsuniontwoconstraintvaluesuniqueness
Problem
Using postgresql 9.5, assume I have a table:
I want to guarantee that the union of values in
For example,
The latter two INSERTs should fail.
CREATE TABLE t (
id INT,
primary TEXT,
secondary TEXT
)I want to guarantee that the union of values in
primary and secondary does not contain duplicates. Is this doable via index/checks or do I have to go to a trigger?For example,
INSERT INTO t(id, primary, secondary) VALUES(1, 'a', 'b');
INSERT INTO t(id, primary, secondary) VALUES(1, 'x', 'y');
INSERT INTO t(id, primary, secondary) VALUES(1, 'a', 'z');
INSERT INTO t(id, primary, secondary) VALUES(1, 'z', 'a');The latter two INSERTs should fail.
Solution
A trigger solution might work but I'd prefer to normalize the design and have simple constraints:
The table that is now:
would become:
Then your inserts
would become:
Finally you can have the original output with:
The table that is now:
CREATE TABLE t (
id INT PRIMARY KEY,
t_primary TEXT,
t_secondary TEXT
) ;would become:
CREATE TABLE tt (
id INT,
t_no SMALLINT NOT NULL,
t_text TEXT,
PRIMARY KEY (id, t_no)
UNIQUE (t_text),
CHECK (t_no IN (1,2))
) ;Then your inserts
INSERT INTO t (id, t_primary, t_secondary) VALUES (1, 'a', 'b');
INSERT INTO t (id, t_primary, t_secondary) VALUES (2, 'x', 'y');
INSERT INTO t (id, t_primary, t_secondary) VALUES (3, 'a', 'z');
INSERT INTO t (id, t_primary, t_secondary) VALUES (4, 'z', 'a');would become:
INSERT INTO tt (id, t_no, t_text) VALUES (1, 1, 'a'), (1, 2, 'b');
INSERT INTO tt (id, t_no, t_text) VALUES (2, 1, 'x'), (2, 2, 'y');
INSERT INTO tt (id, t_no, t_text) VALUES (3, 1, 'a'), (3, 2, 'z'); -- will fail
INSERT INTO tt (id, t_no, t_text) VALUES (4, 1, 'z'), (4, 2, 'a'); -- will failFinally you can have the original output with:
CREATE VIEW t AS
SELECT
a.id,
a.t_text as t_primary,
b.t_text as t_secondary,
FROM tt AS a
JOIN tt AS b
ON a.id = b.id AND a.t_no = 1 AND b.t_no = 2 ;
SELECT *
FROM t ;Code Snippets
CREATE TABLE t (
id INT PRIMARY KEY,
t_primary TEXT,
t_secondary TEXT
) ;CREATE TABLE tt (
id INT,
t_no SMALLINT NOT NULL,
t_text TEXT,
PRIMARY KEY (id, t_no)
UNIQUE (t_text),
CHECK (t_no IN (1,2))
) ;INSERT INTO t (id, t_primary, t_secondary) VALUES (1, 'a', 'b');
INSERT INTO t (id, t_primary, t_secondary) VALUES (2, 'x', 'y');
INSERT INTO t (id, t_primary, t_secondary) VALUES (3, 'a', 'z');
INSERT INTO t (id, t_primary, t_secondary) VALUES (4, 'z', 'a');INSERT INTO tt (id, t_no, t_text) VALUES (1, 1, 'a'), (1, 2, 'b');
INSERT INTO tt (id, t_no, t_text) VALUES (2, 1, 'x'), (2, 2, 'y');
INSERT INTO tt (id, t_no, t_text) VALUES (3, 1, 'a'), (3, 2, 'z'); -- will fail
INSERT INTO tt (id, t_no, t_text) VALUES (4, 1, 'z'), (4, 2, 'a'); -- will failCREATE VIEW t AS
SELECT
a.id,
a.t_text as t_primary,
b.t_text as t_secondary,
FROM tt AS a
JOIN tt AS b
ON a.id = b.id AND a.t_no = 1 AND b.t_no = 2 ;
SELECT *
FROM t ;Context
StackExchange Database Administrators Q#149215, answer score: 3
Revisions (0)
No revisions yet.