【问题标题】:Test ARRAY whether it contains ALL or NO elements of given ARRAY测试 ARRAY 是否包含给定 ARRAY 的 ALL 或 NO 元素
【发布时间】:2021-04-26 11:04:42
【问题描述】:

假设我们有一个数组:

ARRAY[1,2,3]

通过运算符

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

上面的效果很好,但现在让我们看下面的例子:

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

在这种情况下,上面将按预期返回 false。

我们是否有这样的操作符:

  • 左数组包含在右数组中
  • 或者左侧数组中的每个元素都不包含在右侧数组中?

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

我正在使用 PostgreSQL 13。

【问题讨论】:

  • 所有integer 数字都像您的示例所暗示的那样吗? int4 ?可以有 NULL 值作为元素或 NULL 数组吗?如果是这样,如何处理这些?数组元素总是唯一的吗?

标签: sql arrays postgresql operators postgresql-13


【解决方案1】:

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

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

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

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小提琴here

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

但是……

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

不能使用任何索引。见:

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

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

【讨论】:

    【解决方案2】:

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

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

    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];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 2013-04-23
      相关资源
      最近更新 更多