postgresql 如何将ARRAY包含运算符与ANY一起使用

tyky79it  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(3)|浏览(347)

我有一个表,其中一列是数组:

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 column包含数组中单词子集的行。例如input:

ARRAY[ARRAY['A','C'], ARRAY['F'], ARRAY['E']]::text[][]

我想找到所有包含('A' and 'C')OR('F')OR('E')的行。因此,例如上面的例子,我应该得到具有id的行:一、二、五。
我希望我可以使用这样的语法:

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['...

波斯特格雷斯9.6
plpgsql解决方案可以接受,但首选SQL。
DB-FIDDLE:https://www.db-fiddle.com/f/cKCr7Sfab6u8rqaCHhJvPk/0

nkkqxpd9

nkkqxpd91#

问题是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'上迭代。

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']元素来迭代它,你被迫去最深的层次。

uxh89sit

uxh89sit2#

我不认为您可以用一个条件做到这一点,因为“包含AC”的要求。

SELECT * 
FROM inherited_tags 
WHERE tags @> ARRAY['A','C']
   OR tags && array['F', 'E'];

tags @> ARRAY['A','C']选择tags包含ARRAY['A','C']所有元素的行,tags && array['F', 'E']选择至少包含array['F', 'E']中一个标记的行
更新的DB Fiddle:https://www.db-fiddle.com/f/rXsjqEN3ry67uxJtEs3GM9/0

dxxyhpgq

dxxyhpgq3#

你可以试试

SELECT * FROM table WHERE 
    tags @> ARRAY['A','C']::varchar[]
       OR
    tags @> ARRAY['E']::varchar[]
       OR
    tags @> ARRAY['F']::varchar[]

相关问题