比较数组是否相等,忽略元素的顺序

时间:2012-10-13 05:00:13

标签: arrays postgresql

我有一个包含4个数组列的表..结果如下:

ids       signed_ids   new_ids   new_ids_signed
{1,2,3} | {2,1,3}    | {4,5,6} | {6,5,4}

无论如何要通过忽略元素的顺序来比较idssigned_ids以使它们相等?

5 个答案:

答案 0 :(得分:16)

您可以使用运营商包含的内容:

(array1< @ array2 and array1 @> array2)

答案 1 :(得分:12)

处理整数数组,您可以安装扩展程序intarray

每个数据库安装一次(在Postgres 9.1或更高版本中):

CREATE EXTENSION intarray;

然后你可以:

SELECT uniq(sort(ids)) = uniq(sort(signed_ids));

或者:

SELECT ids @> signed_ids AND ids <@ signed_ids;

大胆强调来自intarray的功能和操作员。 两个表达式都将忽略元素的顺序和重复性。有用的手册here中有关这些功能和操作员的更多信息。

注意:

  • intarray运算符仅适用于integer,而不是bigintsmallint或任何其他数据类型的数组。
  • 您可以在不安装@>的情况下使用包含运算符<@intarray,因为标准Postgres分发中的数组类型有通用变体。 intarray仅为int[]安装专用运算符,这些运算符通常更快。
  • 与通用运算符不同,intarray不接受数组中的NULL值,这可能令人困惑:如果在任何涉及的数组中有NULL,则现在会收到错误消息。
    如果您需要使用NULL值,则可以通过使用OPERATOR构造对运算符进行模式限定来默认为标准的泛型运算符

    SELECT ARRAY[1,4,null,3]::int[] OPERATOR(pg_catalog.@>) ARRAY[3,1]::int[]

    相关:

  • 泛型运算符不能使用intarray运算符类的索引,反之亦然。

答案 2 :(得分:10)

最简单的方法是对它们进行排序并对它们进行排序。请参阅sorting arrays in PostgreSQL

给出样本数据:

CREATE TABLE aa(ids integer[], signed_ids integer[]);
INSERT INTO aa(ids, signed_ids) VALUES (ARRAY[1,2,3], ARRAY[2,1,3]);

最好的办法是,如果数组条目总是整数,则使用intarray扩展名为Erwin explains in his answer。它比任何纯SQL公式都快很多

否则,对于适用于任何数据类型的通用版本,请定义array_sort(anyarray)

CREATE OR REPLACE FUNCTION array_sort(anyarray) RETURNS anyarray AS $$
SELECT array_agg(x order by x) FROM unnest($1) x;
$$ LANGUAGE 'SQL';

并使用它对排序的数组进行排序和比较:

SELECT array_sort(ids) = array_sort(signed_ids) FROM aa;

有一个重要的警告:

SELECT array_sort( ARRAY[1,2,2,4,4] ) = array_sort( ARRAY[1,2,4] );

将是假的。根据您的意图,这可能是您想要的,也可能不是。


或者,定义一个函数array_compare_as_set

CREATE OR REPLACE FUNCTION array_compare_as_set(anyarray,anyarray) RETURNS boolean AS $$
SELECT CASE
  WHEN array_dims($1) <> array_dims($2) THEN
    'f'
  WHEN array_length($1,1) <> array_length($2,1) THEN
    'f'
  ELSE
    NOT EXISTS (
        SELECT 1
        FROM unnest($1) a 
        FULL JOIN unnest($2) b ON (a=b) 
        WHERE a IS NULL or b IS NULL
    )
  END
$$ LANGUAGE 'SQL' IMMUTABLE;

然后:

SELECT array_compare_as_set(ids, signed_ids) FROM aa;

这与比较两个array_sort ed值略有不同。 array_compare_as_set将消除重复项,使array_compare_as_set(ARRAY[1,2,3,3],ARRAY[1,2,3])为真,而array_sort(ARRAY[1,2,3,3]) = array_sort(ARRAY[1,2,3])则为假。

这两种方法都会有相当糟糕的表现。请考虑确保始终将数组存储在第一位。

答案 3 :(得分:0)

如果您的数组没有重复且尺寸相同:

  • 使用数组包含@>
  • array_length的长度必须与您想要的两边的大小都匹配

答案 4 :(得分:-1)

  

从以下选项中选择(string_agg(a,','by a order)= string_agg(b,','by b order))   (选择unnest(array [1,2,3,2]):: text为a,unnest(array [2,2,3,1]):: text如b)A