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

时间:2017-07-05 16:45:05

标签: postgresql geometry postgresql-9.6

鉴于此表:

 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)';

3 个答案:

答案 0 :(得分:1)

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

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

如果您有很多事情值得为路径构建索引,这将在类似查询中使用(您需要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

答案 1 :(得分:1)

Postgres中没有可以满足假设的原生几何运算符。您可以使用点数组而不是路径,但是它需要一些准备和作为超级用户的访问。

您需要为类型point创建一个运算符类,以便比较此类型的值。这篇文章描述了整个过程:Creating custom “equality operator” for PostgreSQL type (point).这里有一个我在我的一个项目中需要的代码副本:Postgres class point_ops.

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

create or replace function is_subpath(point[], point[])
returns boolean language plpgsql as $$
begin
    for p in 1..cardinality($1) loop
        if $1[p] = $2[1] then
            for s in 2..cardinality($2) loop
                p:= p+ 1;
                if $1[p] <> $2[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)

答案 2 :(得分:-1)

我认为您是通过数据库设计创建的。你应该使用两个表而不仅仅是一个。

如果您遵循第三范式。您的设计与子表有一对多的关系。

子表中将包含四个记录。

如果您遵循Sql如何工作的规范,这将不是问题。当您将多个数据值放在同一个字段中时,Sql不能很好地处理它,它会限制您使用kludge类型的解决方案。