鉴于此表:
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)';
答案 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)%';
答案 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类型的解决方案。