31

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

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

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

4

5 回答 5

37

您可以使用包含的运算符:

(array1 <@ array2 and array1 @> array2)
于 2017-03-02T01:30:45.190 回答
18

附加模块intarray为 的数组integer提供运算符,这些运算符通常(快得多)。每个数据库安装一次(在 Postgres 9.1 或更高版本中):

CREATE EXTENSION intarray;

那么你就可以:

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

或者:

SELECT ids @> signed_ids AND ids <@ signed_ids;

大胆强调来自 intarray 的函数和运算符。
在第二个示例中,如果 left 和 right 参数是 type ,则运算符解析到达专门的 intarray 运算符integer[]

这两个表达式都将忽略元素的顺序和重复性。在此处的有用手册中进一步阅读。

intarray运算符仅适用于integer( int4) 的数组,而不适用于bigint( int8) 或smallint( int2) 或任何其他数据类型。

与默认的泛型运算符不同,intarray运算符不接受数组中的 NULL 值。任何涉及的数组中的 NULL 都会引发异常。如果您需要使用 NULL 值,您可以默认使用标准的通用运算OPERATOR符,方法是使用构造对运算符进行模式限定:

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

通用运算符不能将索引intarray运算符类一起使用,反之亦然。

有关的:

于 2012-10-13T06:14:40.957 回答
14

最简单的做法是对它们进行排序并比较它们的排序。请参阅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 在他的回答中解释的那样。它任何纯 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])将是错误的。

这两种方法的性能都会很差。考虑确保您始终首先存储已排序的数组。

于 2012-10-13T05:15:32.867 回答
0

如果您的数组没有重复并且具有相同的维度

  • 使用数组包含@>
  • 并且array_length长度必须与两边的尺寸相匹配
于 2020-08-05T08:11:44.243 回答
-1

select (string_agg(a,',' order by a) = string_agg(b,',' order by b)) from (select unnest(array[1,2,3,2])::text as a,unnest(数组[2,2,3,1])::text as b) A

于 2019-08-12T11:15:25.607 回答