在 Postgres 中使用路径子集进行查询

Query using subset of path in Postgres

鉴于此 table:

 id |            points (path)                 |
----+------------------------------------------+
  1 | ((1,2),(3,4),(5,6),(7,8))                |

是否可以使用单个几何运算符和路径参数(包含路径的顺序子集)实现以下目标,如((3,4),(5,6))

select * from things where points @> '(3,4)' and points @> '(5,6)';

也许只是将其转换为字符串并使用 LIKE 进行匹配(您需要 double 因为路径已关闭):

select points::text  from things 
where (points::text || points::text) like '%(3,4),(5,6)%';

如果你有很多东西值得为路径建立索引,这将在like查询中使用(你需要trgm extension

CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX thing_text_paths ON things USING gin ( (points::text || points::text) gin_trgm_ops);

你可以通过运行看到

SET enable_seqscan = OFF;
EXPLAIN select points::text  from things 
where (points::text || points::text) like '%(3,4),(5,6)%';

参见 http://sqlfiddle.com/#!17/bd760/2/0

Postgres 中没有可以满足这些假设的本地几何运算符。您可以使用点数组而不是路径,但是它需要一些准备工作并以超级用户身份访问。

您需要为类型 point 创建一个运算符 class 以允许比较此类型的值。 post 中描述了整个过程: Here you have a copy of my code I needed in one of my projects: Postgres class point_ops.

数组的解决方案需要一个简单的函数,您可以使用它来代替运算符:

create or replace function is_subpath(point[], point[])
returns boolean language plpgsql as $$
begin
    for p in 1..cardinality() loop
        if [p] = [1] then
            for s in 2..cardinality() loop
                p:= p+ 1;
                if [p] <> [s] then
                    return false;
                end if;
                return true;
            end loop;
        end if;
    end loop;
    return false;
end $$;

drop table if exists things;
create table things(
    id int,
    points point[]
);
insert into things values
(1, '{"(3,4)","(1,2)","(5,6)","(7,8)"}'),
(2, '{"(1,2)","(3,4)","(5,6)","(7,8)"}');

select * 
from things 
where is_subpath(points, '{"(3,4)","(5,6)"}'::point[]);

 id |              points               
----+-----------------------------------
  2 | {"(1,2)","(3,4)","(5,6)","(7,8)"}
(1 row)

我认为问题是由您的数据库设计造成的。您应该使用两个 table 而不是一个。

如果你遵循第三范式。您的设计将与 child table 具有一对多关系。

child table 将有四个记录。

如果您遵循 Sql 的工作规范,这将不是问题。当您在同一个字段中放置多个数据值时,Sql 无法很好地处理,它限制了您使用杂乱无章的解决方案。