我有一张表,其中包含世界地图的分区。通过将所有区域分成矩形来完成分区,称为“tile”。像往常一样,矩形有左下角和右上角,两者都是浮点坐标。
任务是:
对于每个磁贴,将其邻居放在右边,将其邻居放到顶部,就像一组{tile_id, id_of_top_neighbour, id_of_right_n}
一样。
通过图块A的右邻居意味着这样的图块B,其具有与A的max_x坐标最接近的min_x坐标,而y是相同的。
表格说明:
integer tile_id; --Tile id. PK.
real min_x; --X coordinate of bottom-left point
real min_y; --Y coordinate of bottom-left point
real max_x; --X coordinate of upper-right point
real max_y; --Y coordinate of upper-right point
解决方案失败:
首先,我尝试按一个坐标排序,在java端迭代此结果集,然后对每一行执行额外的选择。表现不佳。
现在我想知道在运行时是否可以使用纯SQL解决方案......
事先赞赏任何帮助或想法。
修改 两个瓦片之间可能存在间隙,因此(例如,对于右邻居)B.min_x-A.max_x可以是> 0.Hovewer,两个瓷砖不能相交,而不是边界。
我们正在使用Postgres 8.3
答案 0 :(得分:1)
窗口函数和CTE会使这很容易。我认为两者都可以在8.4及以上版本中使用。我强烈建议你升级。我在9.0上测试了这个解决方案:
with tile_data as
(
select
tile_id,
min_x,
min_x + 0.9 as max_x,
min_y,
min_y + 0.9 as max_y
from
(
select 1 as tile_id, 0.0 as min_x, 0.0 as min_y union all
select 2, 1.0, 0.0 union all
select 3, 2.0, 0.0 union all
select 4, 0.0, 1.0 union all
select 5, 1.0, 1.0 union all
select 6, 2.0, 1.0 union all
select 7, 0.0, 2.0 union all
select 8, 1.0, 2.0 union all
select 9, 2.0, 2.0
) a
),
right_neighbor_tiles as
(
select
tile_id,
other_tile_id as right_neighbor_tile_id
from
(
select
a.tile_id,
b.tile_id as other_tile_id,
row_number() over(partition by a.tile_id order by b.min_x - a.min_x) as distance_rank
from
tile_data a
inner join
tile_data b
on
a.min_x < b.min_x
and a.min_y = b.min_y
) ranked_tiles_right
where
distance_rank = 1
),
up_neighbor_tiles as
(
select
tile_id,
other_tile_id as up_neighbor_tile_id
from
(
select
a.tile_id,
b.tile_id as other_tile_id,
row_number() over(partition by a.tile_id order by a.min_y - b.min_y) as distance_rank
from
tile_data a
inner join
tile_data b
on
a.min_y > b.min_y
and a.min_x = b.min_x
) ranked_tiles_up
where
distance_rank = 1
)
select
a.*,
b.right_neighbor_tile_id,
c.up_neighbor_tile_id
from
tile_data a
left join
right_neighbor_tiles b
on
a.tile_id = b.tile_id
left join
up_neighbor_tiles c
on
a.tile_id = c.tile_id
结果:
tile_id min_x max_x min_y max_y right_neighbor_tile_id up_neighbor_tile_id
1 0 0.9 0 0.9 2
2 1 1.9 0 0.9 3
3 2 2.9 0 0.9
4 0 0.9 1 1.9 5 1
5 1 1.9 1 1.9 6 2
6 2 2.9 1 1.9 3
7 0 0.9 2 2.9 8 4
8 1 1.9 2 2.9 9 5
9 2 2.9 2 2.9 6
答案 1 :(得分:0)
更改您的数据以使用Box类型。
create temp table test (
nick char,
tile box
);
/*
.........
aa..bbcc.
aa..bbcc.
*/
insert into test values ('a', box(point(0,1),point(1,0)));
insert into test values ('b', box(point(4,0),point(5,1)));
insert into test values ('c', box(point(7,0),point(8,1)));
select
distinct on (test.nick)
test.nick,
r.nick as right,
least((r.tile[0])[0], (r.tile[1])[0]) as least_x -- gets the lowest x cord
from test
join test as r
on test.tile << r.tile -- strictly left of operator
group by test.nick, right, least_x
输出:
nick | right | least_x
------+---------+---------
a | b | 4
b | c | 7
(2 rows)