【问题标题】:PostgreSQL: 'operator is not unique' for array even with explicit type castPostgreSQL:即使使用显式类型转换,数组的“运算符不是唯一的”
【发布时间】:2021-03-17 08:32:38
【问题描述】:

我正在使用 PostgreSQL v9.2.8 处理遗留系统我尝试运行查询:

SELECT ARRAY['a', 'b']::text[] && ARRAY['a', 'c', 'd']::text[];

最终出现错误:

ERROR:  operator is not unique: text[] && text[]
LINE 1: select array['a', 'b']::text[] && array['a', 'c', 'd']::text...
                                       ^
HINT:  Could not choose a best candidate operator. You might need to add explicit type casts.

与这里提出的许多关于类似问题的问题不同,类型是指定的,我在这里不能更明确。 我需要提一下扩展:btree_ginbtree_gistintarray 已安装,但我无法为文本数组发现任何重复的运算符。

跑步:


SELECT oprname, oprcode,
    l_arg.typname l_arg_type, l_arg.typcategory l_arg_cat,
    r_arg.typname r_arg_type, r_arg.typcategory r_arg_cat
FROM pg_operator o 
JOIN pg_namespace n ON n.oid = o.oprnamespace 
    join pg_type l_arg on l_arg.oid = o.oprleft
    join pg_type r_arg on r_arg.oid = o.oprright
WHERE oprname ilike '%&&%' 

显示:

| oprname | oprcode        | l_arg_type | l_arg_cat | r_arg_type | r_arg_cat |
|---------|----------------|------------|-----------|------------|-----------|
| &&      | poly_overlap   | polygon    | G         | polygon    | G         | 
| &&      | box_overlap    | box        | G         | box        | G         | 
| &&      | tintervalov    | tinterval  | T         | tinterval  | T         | 
| &&      | circle_overlap | circle     | G         | circle     | G         | 
| &&      | arrayoverlap   | anyarray   | P         | anyarray   | P         | 
| &&      | tsquery_and    | tsquery    | U         | tsquery    | U         | 
| &&      | range_overlaps | anyrange   | P         | anyrange   | P         | 
| &&      | _int_overlap   | _int4      | A         | _int4      | A         | 
------------------------------------------------------------------------------

列出运营商家族:

SELECT am.amname AS index_method,
       opf.opfname AS opfamily_name,
       amop.amopopr::regoperator::text AS opfamily_operator
FROM pg_am am, pg_opfamily opf, pg_amop amop
WHERE opf.opfmethod = am.oid AND
      amop.amopfamily = opf.oid
      and amop.amopopr::regoperator::text ilike '%&&%'::text
ORDER BY index_method, opfamily_name, opfamily_operator;

表演

-------------------------------------------------------------
| index_method | opfamily_name    | opfamily_operator       |
|--------------|------------------|-------------------------|
| gin          | array_ops        | &&(anyarray,anyarray)   |
| gin          | gin__int_ops     | &&(integer[],integer[]) |
| gist         | box_ops          | &&(box,box)             |
| gist         | circle_ops       | &&(circle,circle)       |
| gist         | gist__int_ops    | &&(integer[],integer[]) |
| gist         | gist__intbig_ops | &&(integer[],integer[]) |
| gist         | poly_ops         | &&(polygon,polygon)     |
| gist         | range_ops        | &&(anyrange,anyrange)   |
-------------------------------------------------------------

这个问题是否与 &&(anyarray,anyarray) 和两个 &&(integer[],integer[]) 运营商之间的一些奇怪的冲突有关?

我最终想要实现的是创建一个两列 gin 索引

CREATE INDEX concurrently public_some_table_index
ON public.some_table
USING gin
(  (array[text_col_01, text_col_02])  COLLATE pg_catalog."default" _text_ops );

应该用在类似的查询中

SELECT * FROM public.some_table foo
WHERE
(array[foo.text_col_01, foo.text_col_02]) && array['abc', 'def', 'ghi', 'jkl']::text[]

索引创建结果很好。如上所述,仅在查询中使用 && 会失败。

更新:

按照jjanes 的建议,在恢复架构转储 (pg_dump -s) 后,我检查了 Postgresql 9.2.8 的全新安装。问题依然存在。

【问题讨论】:

  • 对于它的价值:您的代码在 Postgres 9.5 中工作(这是 dbfiddle 上最旧的可用版本):dbfiddle.uk/…。有升级计划吗?
  • 是的,我相信这与此特定服务器的配置/扩展有关。我只是没有想法可以检查。还是谢谢。
  • 我无法在 9.2.24 中仅使用您提到的 3 个扩展来重现这一点。如果您使用 pg_dump -s 转储并恢复到新的 9.2 实例,它会在那里重现吗?
  • 您正在使用的 9.2 实例的次要版本是什么?
  • @AdrianKlaver 次要版本是 9.2.8 我会尽可能用新的实例检查这个。

标签: sql postgresql indexing operators postgresql-9.2


【解决方案1】:

当我尝试将仅模式转储还原到全新安装时,错误仍然存​​在。我正在处理的这个特定集群可能存在一些问题。但我真的可以告诉它是什么。 此外,由于不支持 PostgreSQL 9.2,因此很难期待对我的问题提供大量反馈。

我想分享一下我为克服这个障碍所做的工作。

最后我在 public 架构中创建了新函数

CREATE OR REPLACE FUNCTION textarray_overlap(text[], text[])
  RETURNS boolean AS
  $BODY$
    SELECT pg_catalog.arrayoverlap($1, $2);
  $BODY$
  LANGUAGE sql STABLE SECURITY DEFINER
  COST 100;
ALTER FUNCTION textarray_overlap(text[], text[])
  OWNER TO postgres;
GRANT EXECUTE ON FUNCTION textarray_overlap(text[], text[]) TO postgres;
GRANT EXECUTE ON FUNCTION textarray_overlap(text[], text[]) TO public;

该函数将文本数组作为参数并仅调用内置pg_catalog.arrayoverlap(annyaray, anyarray)。 有了它,我为使用此函数的文本数组创建了新的 && 运算符。

CREATE OPERATOR &&(
  PROCEDURE = textarray_overlap,
  LEFTARG = text[],
  RIGHTARG = text[],
  COMMUTATOR = &&,
  RESTRICT = contsel,
  JOIN = contjoinsel);
COMMENT ON OPERATOR &&(text[], text[]) IS 'overlap';

这解决了我的问题,因为我想现在服务器有专门的运算符来检查文本数组是否重叠。

SELECT ARRAY['a', 'b']::text[] && ARRAY['a', 'c', 'd']::text[];

返回TRUE

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-14
    • 2015-08-25
    • 2018-04-14
    • 2013-04-29
    • 2017-12-21
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    相关资源
    最近更新 更多