问题
Given the following three columns in a Postgres database: first, second, third; how can I create a constraint such that permutations are unique?
E.g. If ('foo', 'bar', 'shiz')
exist in the db, ('bar', 'shiz', 'foo')
would be excluded as non-unique.
回答1:
You could use hstore to create the unique index:
CREATE UNIQUE INDEX hidx ON test USING BTREE (hstore(ARRAY[a,b,c], ARRAY[a,b,c]));
Fiddle
UPDATE
Actually
CREATE UNIQUE INDEX hidx ON test USING BTREE (hstore(ARRAY[a,b,c], ARRAY[null,null,null]));
might be a better idea since it will work the same but should take less space (fiddle).
回答2:
For only three columns this unique index using only basic expressions should perform very well. No additional modules like hstore or custom function needed:
CREATE UNIQUE INDEX t_abc_uni_idx ON t (
LEAST(a,b,c)
, GREATEST(LEAST(a,b), LEAST(b,c), LEAST(a,c))
, GREATEST(a,b,c)
);
SQL fiddle
Also needs the least disk space:
SELECT pg_column_size(row(hstore(t))) AS hst_row
,pg_column_size(row(hstore(ARRAY[a,b,c], ARRAY[a,b,c]))) AS hst1
,pg_column_size(row(hstore(ARRAY[a,b,c], ARRAY[null,null,null]))) AS hst2
,pg_column_size(row(ARRAY[a,b,c])) AS arr
,pg_column_size(row(LEAST(a,b,c)
, GREATEST(LEAST(a,b), LEAST(b,c), LEAST(a,c))
, GREATEST(a,b,c))) AS columns
FROM t;
hst_row | hst1 | hst2 | arr | columns
---------+------+------+-----+---------
59 | 59 | 56 | 69 | 30
Numbers are bytes for index row in the example in the fiddle, measured with pg_column_size(). My example uses only single characters, the difference in size is constant.
回答3:
You can do this by creating a unique index on a function which returns a sorted array of the values in the columns:
CREATE OR REPLACE FUNCTION sorted_array(anyarray)
RETURNS anyarray
AS $BODY$
SELECT array_agg(x) FROM (SELECT unnest($1) AS x FROM test ORDER BY x) AS y;
$BODY$
LANGUAGE sql IMMUTABLE;
CREATE UNIQUE index ON test (sorted_array(array[first,second,third]));
回答4:
Suggestion from co-worker, variation of @julien's idea:
Sort the terms alphabetically and place a delimiter on either side of each term. Concatenate them and place them in a separate field that becomes the primary key.
Why the delimiter? So that, "a", "aa", "aaa" and "aa", "aa", "aa" can both be inserted.
来源:https://stackoverflow.com/questions/18360173/unique-constraint-for-permutations-across-multiple-columns