postgresql Postgres UNIQUE CONSTRAINT for array

yyhrrdl8  于 2023-03-29  发布在  PostgreSQL
关注(0)|答案(3)|浏览(473)

如何对所有值的唯一性创建约束 在数组中:

CREATE TABLE mytable
(
    interface integer[2],
    CONSTRAINT link_check UNIQUE (sort(interface))
)

我的排序函数

create or replace function sort(anyarray)
returns anyarray as $$
select array(select $1[i] from generate_series(array_lower($1,1),
array_upper($1,1)) g(i) order by 1)
$$ language sql strict immutable;

我需要将值{10,22}和{22,10}视为相同,并在唯一约束下进行检查

gzszwxb4

gzszwxb41#

我不认为你可以使用一个带有唯一约束的函数,但是你可以使用unique index,所以给定一个排序函数如下:

create function sort_array(anyarray) returns anyarray as $$
    select array_agg(distinct n order by n) from unnest($1) as t(n);
$$ language sql immutable;

然后你可以这样做:

create table mytable (
    interface integer[2] 
);
create unique index mytable_uniq on mytable (sort_array(interface));

然后发生以下情况:

=> insert into mytable (interface) values (array[11,23]);
INSERT 0 1
=> insert into mytable (interface) values (array[11,23]);
ERROR:  duplicate key value violates unique constraint "mytable_uniq"
DETAIL:  Key (sort_array(interface))=({11,23}) already exists.
=> insert into mytable (interface) values (array[23,11]);
ERROR:  duplicate key value violates unique constraint "mytable_uniq"
DETAIL:  Key (sort_array(interface))=({11,23}) already exists.
=> insert into mytable (interface) values (array[42,11]);
INSERT 0 1
g52tjvyc

g52tjvyc2#

mu已经演示了index on an expression如何解决您的问题。
我的注意力被使用的函数吸引住了。对于两个整数的数组来说,这两个函数似乎都有些矫枉过正。这可能是真实的情况的简化?无论哪种方式,我都很感兴趣,并用几个变体进行了测试。

测试设置

具有10000个随机整数对的临时表:

CREATE TEMP TABLE arr (i int[]);

INSERT INTO arr 
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM   generate_series(1,10000);

用简短的评论来解释每一个测试候选人:

  1. Mu的查询
CREATE OR REPLACE FUNCTION sort_array1(integer[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
    SELECT array_agg(n) FROM (SELECT n FROM unnest($1) AS t(n) ORDER BY n) AS a;
$func$;

1.与ORDER BY内部聚集体相同(第9.0页以上)

CREATE OR REPLACE FUNCTION sort_array2(int[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT array_agg(n ORDER BY n) FROM unnest($1) AS t(n);
$func$;
  1. uralbash的查询
CREATE OR REPLACE FUNCTION sort_array3(anyarray)
  RETURNS anyarray
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT ARRAY(
    SELECT $1[i]
    FROM   generate_series(array_lower($1,1), array_upper($1,1)) g(i)
    ORDER  BY 1)
$func$;

1.将参数更改为int[]

CREATE OR REPLACE FUNCTION sort_array4(int[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT ARRAY(
    SELECT $1[i]
    FROM   generate_series(array_lower($1,1), array_upper($1,1)) g(i)
    ORDER  BY 1)
$func$;

1.简化array_lower()-始终为1

CREATE OR REPLACE FUNCTION sort_array5(int[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT ARRAY(
    SELECT $1[i]
    FROM   generate_series(1, array_upper($1,1)) g(i)
    ORDER  BY 1)
$func$;

1.进一步简化为具有2个元件的情况

CREATE OR REPLACE FUNCTION sort_array6(int[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT ARRAY(
    SELECT i
    FROM  (VALUES ($1[1]),($1[2])) g(i)
    ORDER  BY 1)
$func$;

1.我的简单查询

CREATE OR REPLACE FUNCTION sort_array7(int[])
  RETURNS int[]
  LANGUAGE sql STRICT IMMUTABLE AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;

1.不使用STRICT修饰符(!)

CREATE OR REPLACE FUNCTION sort_array8(int[])
  RETURNS int[]
  LANGUAGE sql IMMUTABLE AS
$func$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$func$;

结果

我分别执行了大约20次,并从EXPLAIN ANALYZE中获得了最佳结果。

SELECT sort_array1(i) FROM arr  -- Total runtime: 183 ms
SELECT sort_array2(i) FROM arr  -- Total runtime: 175 ms

SELECT sort_array3(i) FROM arr  -- Total runtime: 183 ms
SELECT sort_array4(i) FROM arr  -- Total runtime: 183 ms
SELECT sort_array5(i) FROM arr  -- Total runtime: 177 ms
SELECT sort_array6(i) FROM arr  -- Total runtime: 144 ms

SELECT sort_array7(i) FROM arr  -- Total runtime: 103 ms
SELECT sort_array8(i) FROM arr  -- Total runtime:  43 ms (!!!)

这些是在Debian Squeeze上的v9.0.5服务器上的结果。v.8.4上的结果类似。
我还测试了PL/pgSQL变体,它们的速度比预期的要慢一些:对于一个小操作来说开销太大,没有查询计划要缓存。

**简单函数(编号7)比其他函数快得多。这是意料之中的,其他变体的开销对于一个小数组来说太多了。

离开STRICT声明超过加倍的速度。我没想到,并张贴了以下后续发现原因:

wlwcrazw

wlwcrazw3#

只需在两个值上创建一个唯一索引:

create unique index ix on 
  mytable(least(interface[1], interface[2]), greatest(interface[1], interface[2]));

相关问题