测试 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
(也没有内置运算符)可能会更快地实现。
假设我们有一个数组:
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
(也没有内置运算符)可能会更快地实现。