每个部分(字母)是一个单一的对象,颜色是对象的相关属性。
代表这个的表是这样定义的 。
CREATE TABLE lines (gid text, color text, startpoint integer, endpoint integer);
INSERT INTO lines (gid, color, startpoint, endpoint)
VALUES
('A','green', 1, 2),
('B','green', 2, 3),
('C','green', 3, 4),
('D','green', 4, 5),
('E','red', 2, 6),
('F','red', 6, 7),
('G','red', 7, 8),
('H','blue', 3, 9),
('I','blue', 4, 10),
('J','blue', 10, 11);
我想得到的结果是由所有相互接触的相同颜色的对象组成的集合对象。所以这里应该是4个对象:{A,B,C,D},{E,F,G},{H}和{I,J}。我认为应该使用开始点和结束点的值,因为它们决定了对象的接触方面。
目前我像下面的代码一样,使用了一个 JOIN
所以对象H被返回(如果我使用一个 WHERE
句子,同 ON
条件下,H不会被返回,因为它永远不会匹配startpointendpoint的相关性)。
SELECT a.gid, b.gid, a.color
FROM lines a
LEFT JOIN lines b ON a.gid > b.gid AND (a.startpoint = b.endpoint OR a.endpoint = b.startpoint) AND a.color = b.color
有了这个结果。
从这里我不知道该怎么做。我在PostGIS中使用了一个聚合函数来合并行,所以我想我需要有这样的结果(这样我就可以运行一个查询,用 GROUP BY
) :
有谁知道有什么方法可以做我想做的事情?
假设你的数据没有圆圈,如你的样本数据所示,一个选择是使用递归查询。
其想法是首先确定每个颜色的所有起始点。为此,你可以使用 not exsits
:
select l.*
from lines l
where not exists (
select 1 from lines l1 where l1.endpoint = l.startpoint and l1.color = l.color
)
从那里开始,你可以递归地遍历结构,通过寻找相同颜色的线条,这些线条的起点是前一个线条的终点,同时在一个数组中跟踪线条的路径。
最后一步是过滤结果集以识别非重叠的路径。为此,我们可以使用 not exists
与包含运算符。
请注意,这种技术允许有分支,如果有的话。
代码。
with recursive cte as (
select l.*, array[gid] path
from lines l
where not exists (
select 1 from lines l1 where l1.endpoint = l.startpoint and l1.color = l.color
)
union all
select l.*, c.path || l.gid
from cte c
inner join lines l on l.startpoint = c.endpoint and l.color = c.color
)
select color, path
from cte c
where not exists (select 1 from cte c1 where c1.path @> c.path and not c.path @> c1.path)
order by color, path
颜色