测试 ARRAY 是否包含给定 ARRAY 的 ALL 或 NO 元素

Test ARRAY whether it contains ALL or NO elements of given ARRAY

假设我们有一个数组:

ARRAY[1,2,3]

用运算符<@我可以查询左操作数是否是右操作数的子数组:

ARRAY[1, 2] <@ ARRAY[1,2,3]

上面的方法很有效,但现在让我们来看下面的情况:

ARRAY[1, 2] <@ ARRAY[1,3,7]

在这种情况下,如预期的那样 return 为假。

我们有没有这样的接线员:

到今天为止,我可以很容易地想出一个涉及重叠运算符的解决方案,但这并不是我真正想要的。 它使我的查询变得非常复杂,我需要在应用程序端执行一些更复杂的字符串机制来构建查询。

我正在使用 PostgreSQL 13。

您可以通过检查子数组匹配或零重叠来进行短语表达。

这是真的,因为第一个数组是第二个数组的子数组:

ARRAY[1,2] <@ ARRAY[1,2,3] OR NOT ARRAY[1,2] && ARRAY[1,2,3];

这也是正确的,因为第一个数组不是子数组但它也有零重叠:

ARRAY[4,5] <@ ARRAY[1,2,3] OR NOT ARRAY[4,5] && ARRAY[1,2,3];

没有单个运算符来检查两者(包含无重叠 ).
不在 Postgres 13 中,不在任何标准 Postgres 发行版中。

但你可以轻松create your own operator。我选择运算符名称 <@!&& 是明确的,因为它不会与任何现有运算符冲突。选择你喜欢的,也许更短一些,因为你的目标是短代码。

CREATE FUNCTION f_array_contained_or_no_overlap(anyarray, anyarray)
  RETURNS boolean
  LANGUAGE sql IMMUTABLE AS
'SELECT  <@  OR NOT  && ';

CREATE OPERATOR <@!&& (
  FUNCTION = f_array_contained_or_no_overlap
, LEFTARG  = anyarray
, RIGHTARG = anyarray
);

那么你可以:

SELECT ARRAY[1,2] <@!&& ARRAY[1,2,7] AS contained     -- true
     , ARRAY[1,2] <@!&& ARRAY[4,5,6] AS no_overlap    -- true
     , ARRAY[1,2] <@!&& ARRAY[4,2,6] AS part_overlap; -- false
contained no_overlap part_overlap
t t f

db<>fiddle here

实现您宣称的简短代码目标。
适用于任何数组(任何元素类型),但两个操作数当然必须兼容。

但是...

不允许 NULL 元素,因为底层 generic array operators 也不允许。

不能使用任何索引。参见:

  • Can PostgreSQL index array columns?

如果直接使用底层函数f_array_contained_or_no_overlap(anyarray, anyarray)而不是运算符Postgres should be able to inline it,这样仍然可以使用一个适用的GIN索引

如果都是整数数组,使用附加模块 intarray(也没有内置运算符)可能会更快地实现。