【问题标题】:Unique constraint for permutations across multiple columns跨多列排列的唯一约束
【发布时间】:2013-08-23 23:41:30
【问题描述】:

给定 Postgres 数据库中的以下三列:第一、第二、第三;如何创建一个约束,使排列是唯一的?

例如如果数据库中存在('foo', 'bar', 'shiz'),则('bar', 'shiz', 'foo') 将被排除为非唯一。

【问题讨论】:

  • 我也想知道这个。只是出于好奇。
  • 您的列可以为 NULL 吗?它们可以是空的吗?然后定义“唯一”。你的 Postgres 版本?而且我没有在您的问题中看到用于测试的表定义?
  • 非空。 9.2.2 值都是文本。
  • 您可能希望升级到 9.2.4 以消除 9.2.4 中修补的安全漏洞。更多详情cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1899

标签: sql postgresql database-design constraints unique-constraint


【解决方案1】:

您可以使用 hstore 创建唯一索引:

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

Fiddle

更新

其实

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

可能是一个更好的主意,因为它的工作原理相同,但占用的空间更少 (fiddle)。

【讨论】:

    【解决方案2】:

    对于仅三列,这个仅使用基本表达式的唯一索引应该表现得非常好。不需要额外的模块,如 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

    还需要最少的磁盘空间:

    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
    

    数字是小提琴示例中索引行的字节,用pg_column_size() 测量。我的示例仅使用单个字符,大小的差异是恒定的。

    【讨论】:

    • 巧妙使用 GREATEST 和 LEAST。
    【解决方案3】:

    您可以通过在函数上创建唯一索引来实现此目的,该索引返回列中值的排序数组:

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

    【讨论】:

    • 可能值得检查几个嵌套 CASE 表达式手动排序的性能影响。只有 3 列应该是可行的。不过可能不值得多花时间。
    • 理查德,性能不是这里的驱动程序。小应用程序,一天可能有 20-100 次插入。
    【解决方案4】:

    同事的建议,@julien 想法的变体:

    按字母顺序对术语进行排序,并在每个术语的两侧放置一个分隔符。连接它们并将它们放在一个单独的字段中,成为主键。

    为什么是分隔符?这样,“a”、“aa”、“aaa”和“aa”、“aa”、“aa”都可以插入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 2012-08-10
      • 2010-12-22
      • 2016-08-22
      相关资源
      最近更新 更多