ura*_*ash 14 arrays postgresql unique-constraint
如何创建对数组中所有值的唯一性的约束,如:
CREATE TABLE mytable
(
interface integer[2],
CONSTRAINT link_check UNIQUE (sort(interface))
)
Run Code Online (Sandbox Code Playgroud)
我的排序功能
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;
Run Code Online (Sandbox Code Playgroud)
我需要的是值{10,22}和{22,10}被认为是相同的并且在UNIQUE CONSTRAINT下检查
mu *_*ort 13
我认为您不能使用具有唯一约束的函数,但您可以使用唯一索引.所以给出一个像这样的排序函数:
create function sort_array(integer[]) returns integer[] as $$
select array_agg(n) from (select n from unnest($1) as t(n) order by n) as a;
$$ language sql immutable;
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
create table mytable (
interface integer[2]
);
create unique index mytable_uniq on mytable (sort_array(interface));
Run Code Online (Sandbox Code Playgroud)
然后发生以下情况:
=> 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
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 10
我的注意力被用过的功能所吸引.对于两个整数的数组来说,两者似乎都是过度杀伤力.这可能是对实际情况的简化.(?)
无论如何,我很感兴趣并且使用了几个变体进行了测试.
-- temporary table with 10000 random pairs of integer
CREATE TEMP TABLE arr (i int[]);
INSERT INTO arr
SELECT ARRAY[(random() * 1000)::int, (random() * 1000)::int]
FROM generate_series(1,10000);
Run Code Online (Sandbox Code Playgroud)
测试候选人的简短评论来解释每一个:
-- 1) mu's query
CREATE OR REPLACE FUNCTION sort_array1(integer[]) RETURNS int[] AS
$$
SELECT array_agg(n) FROM (SELECT n FROM unnest($1) AS t(n) ORDER BY n) AS a;
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 2) simplified with ORDER BY inside aggregate (pg 9.0+)
CREATE OR REPLACE FUNCTION sort_array2(int[]) RETURNS int[] AS
$$
SELECT array_agg(n ORDER BY n) FROM unnest($1) AS t(n);
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 3) uralbash's query
CREATE OR REPLACE FUNCTION sort_array3(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;
-- 4) change parameters to int[]
CREATE OR REPLACE FUNCTION sort_array4(int[]) RETURNS int[] 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;
-- 5) simplify array_lower() - it's always 1
CREATE OR REPLACE FUNCTION sort_array5(int[]) RETURNS int[] AS
$$
SELECT ARRAY(
SELECT $1[i]
FROM generate_series(1, array_upper($1,1)) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 6) further simplify to case with 2 elements
CREATE OR REPLACE FUNCTION sort_array6(int[]) RETURNS int[] AS
$$
SELECT ARRAY(
SELECT i
FROM (VALUES ($1[1]),($1[2])) g(i)
ORDER BY 1)
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 7) my radically simple query
CREATE OR REPLACE FUNCTION sort_array7(int[]) RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 8) without STRICT modifier
CREATE OR REPLACE FUNCTION sort_array8(int[]) RETURNS int[] AS
$$
SELECT CASE WHEN $1[1] > $1[2] THEN ARRAY[$1[2], $1[1]] ELSE $1 END;
$$ LANGUAGE sql IMMUTABLE;
Run Code Online (Sandbox Code Playgroud)
我执行了大约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 (!!!)
Run Code Online (Sandbox Code Playgroud)
这些是Debian Squeeze上的v9.0.5服务器的结果.关于v.8.4的类似结果.
我还测试了plpgsql变种,这些变体比预期的要慢一点:对于一个微小的操作来说太多开销,没有缓存的查询计划.
的简单的函数(NR 7)比其它实质上更快.这是可以预料的,其他变种的开销对于一个小阵列来说太多了.
但是,离开STRICT修改器的速度超过了速度的两倍是不可预料的.至少我没有.我在这里发了一个关于这个现象的问题.
只需在两个值上创建唯一索引:
create unique index ix on
mytable(least(interface[1], interface[2]), greatest(interface[1], interface[2]));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4889 次 |
| 最近记录: |