如何将 ARRAY 包含运算符与 ANY 一起使用
How to use ARRAY contains operator with ANY
我有一个 table,其中一列是数组:
CREATE TABLE inherited_tags (
id serial,
tags text[]
);
示例值:
INSERT INTO inherited_tags (tags) VALUES
(ARRAY['A','B','C']), -- id: 1
(ARRAY['D','E']), -- id: 2
(ARRAY['A','B']), -- id: 3
(ARRAY['C','D']), -- id: 4
(ARRAY['D','F']), -- id: 5
(ARRAY['A']); -- id: 6
我想找到 tags 列包含数组中的某些单词子集的行。例如输入:
ARRAY[ARRAY['A','C'], ARRAY['F'], ARRAY['E']]::text[][]
我想查找包含 ('A' 和 'C') OR ('F') OR ('E') 的所有行。因此,对于上面的示例,我应该获取 ID 为:1、2、5 的行。
我希望我可以使用这样的语法:
SELECT * FROM inherited_tags WHERE
tags @> ANY(ARRAY[ARRAY['A','C'], ARRAY['F'], ARRAY['E']]::text[][])
但我得到错误:
ERROR: operator does not exist: text[] @> text
LINE 1: SELECT * FROM inherited_tags where tags <@ ANY(ARRAY[ARRAY['...
Postgres 9.6
plpgsql 解决方案是acceptable,但首选SQL。
DB-FIDDLE: https://www.db-fiddle.com/f/cKCr7Sfab6u8rqaCHhJvPk/0
由于 "contains A and C" 要求,我认为您无法通过单一条件做到这一点。
SELECT *
FROM inherited_tags
WHERE tags @> ARRAY['A','C']
OR tags && array['F', 'E'];
tags @> ARRAY['A','C']
选择那些 tags
包含来自 ARRAY['A','C']
的 all 元素的行,而 tags && array['F', 'E']
选择那些至少包含array['F', 'E']
中的标签之一
更新数据库 Fiddle:https://www.db-fiddle.com/f/rXsjqEN3ry67uxJtEs3GM9/0
问题是因为 text[]
和 text[][]
数据类型在内部是相同的数据类型。数组具有基本类型和维度,ANY
运算符将始终提取基本类型进行比较,它始终是 text
而不是 text[]
。多维数组要求每个子元素的长度彼此相同,这无济于事。您可以 ARRAY[ARRAY['A','C'],ARRAY['B','N']]
,但不能 ARRAY[ARRAY[2,3],ARRAY[1]]
。
简而言之,没有直接的方法可以使特定查询工作。我也尝试为此创建一个函数和一个运算符,但没有用,或者,出于不同的原因。看看进展如何:
CREATE OR REPLACE FUNCTION check_tag_matches(
IN leftside text[],
IN rightside text)
RETURNS BOOLEAN AS
$BODY$
DECLARE rightarr text[];
BEGIN
SELECT CAST(rightside as text[]) INTO rightarr;
RETURN SELECT leftside @> rightarr;
END;
$BODY$
LANGUAGE plpgsql STABLE;
CREATE OPERATOR public.>>(
PROCEDURE = check_tag_matches,
LEFTARG = text[],
RIGHTARG = text,
COMMUTATOR = >>);
然后测试的时候:
test=# SELECT * FROM inherited_tags WHERE
tags >> ANY(ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]);
ERROR: malformed array literal: "A"
DETAIL: Array value must start with "{" or dimension information.
CONTEXT: SQL statement "SELECT CAST(rightside as text[])"
PL/pgSQL function check_tag_matches(text[],text) line 4 at SQL statement
似乎当您尝试在 ANY()
中使用像 ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]
这样的多维数组时,它不会遍历 ARRAY['A','M']
,然后 ARRAY['F','E']
,然后 ARRAY['E','R']
],但超过 'A','M','F','E','E','R'
。使用 unnest
.
时也会发生同样的事情
test=# SELECT unnest(ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]);
unnest
--------
A
M
F
E
E
R
(6 rows)
您剩下的选项是定义一个函数,该函数将读取 array_length(rightside,1)
和 array_length(rightside,2)
并使用嵌套循环检查所有内容,或者您可以发送多个查询以获取每个标签的继承标签,或以某种方式重组您的数据。而且您甚至无法使用 rightside[1]
访问 ARRAY['A','M']
元素以对其进行迭代,您被迫进入最深层次。
你可以试试
SELECT * FROM table WHERE
tags @> ARRAY['A','C']::varchar[]
OR
tags @> ARRAY['E']::varchar[]
OR
tags @> ARRAY['F']::varchar[]
我有一个 table,其中一列是数组:
CREATE TABLE inherited_tags (
id serial,
tags text[]
);
示例值:
INSERT INTO inherited_tags (tags) VALUES
(ARRAY['A','B','C']), -- id: 1
(ARRAY['D','E']), -- id: 2
(ARRAY['A','B']), -- id: 3
(ARRAY['C','D']), -- id: 4
(ARRAY['D','F']), -- id: 5
(ARRAY['A']); -- id: 6
我想找到 tags 列包含数组中的某些单词子集的行。例如输入:
ARRAY[ARRAY['A','C'], ARRAY['F'], ARRAY['E']]::text[][]
我想查找包含 ('A' 和 'C') OR ('F') OR ('E') 的所有行。因此,对于上面的示例,我应该获取 ID 为:1、2、5 的行。
我希望我可以使用这样的语法:
SELECT * FROM inherited_tags WHERE
tags @> ANY(ARRAY[ARRAY['A','C'], ARRAY['F'], ARRAY['E']]::text[][])
但我得到错误:
ERROR: operator does not exist: text[] @> text
LINE 1: SELECT * FROM inherited_tags where tags <@ ANY(ARRAY[ARRAY['...
Postgres 9.6
plpgsql 解决方案是acceptable,但首选SQL。
DB-FIDDLE: https://www.db-fiddle.com/f/cKCr7Sfab6u8rqaCHhJvPk/0
由于 "contains A and C" 要求,我认为您无法通过单一条件做到这一点。
SELECT *
FROM inherited_tags
WHERE tags @> ARRAY['A','C']
OR tags && array['F', 'E'];
tags @> ARRAY['A','C']
选择那些 tags
包含来自 ARRAY['A','C']
的 all 元素的行,而 tags && array['F', 'E']
选择那些至少包含array['F', 'E']
更新数据库 Fiddle:https://www.db-fiddle.com/f/rXsjqEN3ry67uxJtEs3GM9/0
问题是因为 text[]
和 text[][]
数据类型在内部是相同的数据类型。数组具有基本类型和维度,ANY
运算符将始终提取基本类型进行比较,它始终是 text
而不是 text[]
。多维数组要求每个子元素的长度彼此相同,这无济于事。您可以 ARRAY[ARRAY['A','C'],ARRAY['B','N']]
,但不能 ARRAY[ARRAY[2,3],ARRAY[1]]
。
简而言之,没有直接的方法可以使特定查询工作。我也尝试为此创建一个函数和一个运算符,但没有用,或者,出于不同的原因。看看进展如何:
CREATE OR REPLACE FUNCTION check_tag_matches(
IN leftside text[],
IN rightside text)
RETURNS BOOLEAN AS
$BODY$
DECLARE rightarr text[];
BEGIN
SELECT CAST(rightside as text[]) INTO rightarr;
RETURN SELECT leftside @> rightarr;
END;
$BODY$
LANGUAGE plpgsql STABLE;
CREATE OPERATOR public.>>(
PROCEDURE = check_tag_matches,
LEFTARG = text[],
RIGHTARG = text,
COMMUTATOR = >>);
然后测试的时候:
test=# SELECT * FROM inherited_tags WHERE
tags >> ANY(ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]);
ERROR: malformed array literal: "A"
DETAIL: Array value must start with "{" or dimension information.
CONTEXT: SQL statement "SELECT CAST(rightside as text[])"
PL/pgSQL function check_tag_matches(text[],text) line 4 at SQL statement
似乎当您尝试在 ANY()
中使用像 ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]
这样的多维数组时,它不会遍历 ARRAY['A','M']
,然后 ARRAY['F','E']
,然后 ARRAY['E','R']
],但超过 'A','M','F','E','E','R'
。使用 unnest
.
test=# SELECT unnest(ARRAY[ARRAY['A','M'], ARRAY['F','E'], ARRAY['E','R']]::text[][]);
unnest
--------
A
M
F
E
E
R
(6 rows)
您剩下的选项是定义一个函数,该函数将读取 array_length(rightside,1)
和 array_length(rightside,2)
并使用嵌套循环检查所有内容,或者您可以发送多个查询以获取每个标签的继承标签,或以某种方式重组您的数据。而且您甚至无法使用 rightside[1]
访问 ARRAY['A','M']
元素以对其进行迭代,您被迫进入最深层次。
你可以试试
SELECT * FROM table WHERE
tags @> ARRAY['A','C']::varchar[]
OR
tags @> ARRAY['E']::varchar[]
OR
tags @> ARRAY['F']::varchar[]