简体   繁体   English

跨多列排列的唯一约束

[英]Unique constraint for permutations across multiple columns

Given the following three columns in a Postgres database: first, second, third; 给出Postgres数据库中的以下三列:第一,第二,第三; how can I create a constraint such that permutations are unique? 如何创建约束以使排列是唯一的?

Eg If ('foo', 'bar', 'shiz') exist in the db, ('bar', 'shiz', 'foo') would be excluded as non-unique. 例如,如果db中存在('foo', 'bar', 'shiz') ,则('bar', 'shiz', 'foo')将被排除为非唯一。

You could use hstore to create the unique index: 您可以使用hstore创建唯一索引:

CREATE UNIQUE INDEX hidx ON test USING BTREE (hstore(ARRAY[a,b,c], ARRAY[a,b,c]));

Fiddle 小提琴

UPDATE 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 ). 可能是一个更好的主意,因为它会工作相同,但应占用更少的空间( 小提琴 )。

For only three columns this unique index using only basic expressions should perform very well. 对于仅三列,仅使用基本表达式的唯一索引应该表现得非常好。 No additional modules like hstore or custom function needed: 无需其他模块,如hstore或自定义函数:

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 SQL小提琴

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() . 数字是小提琴示例中索引行的字节,用pg_column_size()测量。 My example uses only single characters, the difference in size is constant. 我的例子只使用单个字符,大小差异是不变的。

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]));

Suggestion from co-worker, variation of @julien's idea: 来自同事的建议,@ julien的想法的变化:

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. 这样,“a”,“aa”,“aaa”和“aa”,“aa”,“aa”都可以插入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM