例如,我有一个用户表。每个用户都是地图上的“方形”(或圆圈)。
我想在地图上找到重叠另一个方块的用户。 MySQL 5.6目前是否支持此功能? (那么MySQL的开发版本呢?)
请注意,我不是在寻找“在这个广场内找到一个点的用户”。我正在寻找“找到方形与这个方块重叠的用户(不一定包含;只要两个方块都触摸 - 它很好)”。
如果某人可以提供INSERTING记录的示例,然后使用ST_INTERSECT多边形对它们进行查询,那将非常有用。
答案 0 :(得分:25)
创建包含多边形列的表
请注意,要使用空间索引,您不能使用InnoDB。 您可以使用没有空间索引的几何体,但性能会像往常一样降低。
CREATE TABLE IF NOT EXISTS `spatial` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`poly` geometry NOT NULL,
UNIQUE KEY `id` (`id`),
SPATIAL INDEX `poly` (`poly`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
获取3个方格并插入三角形
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((10 50,50 50,50 10,10 10,10 50))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((1 15,5 15,5 11,1 11,1 15))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((11 5,15 5,15 1,11 5))',0));
选择左下角与小方块相交的所有内容 (紫色方块#1)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
)
;
选择与左下角到右下角到右上角的三角形相交的所有内容 (方块#1和#2以及方格#4。)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
)
;
选择我们图片之外的方格中的所有内容 (无)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
)
;
编辑#1:
我重读了这个问题,我认为你的空间关系有点混乱。如果您想要的是找到适合在正方形(多边形)内的所有东西,那么您需要使用Contains / ST_Contains。请参阅spatial functions in MySQL documentation以了解哪项功能适合您。 请注意ST / MBR功能之间的以下区别:
选择完全在正方形内的所有内容(#0从下面开始) (方块#1,#2,三角形#4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
选择完全在正方形内的所有内容(从下面开始#0)并且不共享边 (方形#2,三角形#4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
编辑#2:
来自@StephanB(SQL fiddle)的非常好的补充
要列出所有交叉点,请将表格连接到自身并过滤掉 反向交叉点
选择任何重叠的对象
SELECT s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)
FROM `spatial` s1, `spatial` s2
WHERE
ST_Intersects(s1.poly, s2.poly)
AND s1.id < s2.id
;
(请注意,如果您使用的是AND s1.id < s2.id
CONTAINS
CONTAINS(a,b) <> CONTAINS(b,a)
,那么您应删除Intersects(a,b) = Intersects(b,a)
在下图(非详尽列表)中:
编辑#3:按距离搜索/在圈子中工作
MySQL不直接支持圆作为几何,但您可以使用空间函数Buffer(geometry,distance)
来解决它。 Buffer()
的作用是创建几何体周围所述距离的缓冲区。如果从几何点开始,缓冲区确实是一个圆圈。
您只需调用:
即可查看实际执行的缓冲区SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))
(结果很长,所以我不会在这里发布它)它实际上创建了表示缓冲区的多边形 - 在这种情况下(和我的MariaDB)结果是126点多边形,它近似了一个圆。使用这样的多边形,您可以像处理任何其他多边形一样工作。所以不应该有性能损失。
因此,如果你想选择所有落入圆圈的多边形,你可以冲洗并重复前面的例子 (这将只找到#3广场)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
选择与圆相交的所有多边形
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
使用与矩形不同的形状时,应使用ST_*
函数。没有ST_
的函数使用边界矩形。因此,前面的示例选择三角形#4,即使它不在圆圈中。
由于Buffer()
创建了相当大的多边形,因此使用ST_Distance()
方法肯定会有一些性能损失。不幸的是我无法量化它。你将不得不做一些基准测试。
按距离查找对象的另一种方法是使用ST_Distance()
函数。
从表中选择所有元素并计算它们与点POINT的距离(6 15)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
;
您也可以在ST_Distance
子句中使用WHERE
。
选择与POINT(0 0)的距离小于或等于10的所有元素(选择#1,#2和#3)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
;
尽管距离是从最近点到最近点计算的。使它类似于ST_Intersect
。所以上面的例子将选择#2,即使它不完全适合圆圈。
是的,GeomFromText(text,srid)
的第二个参数(0)没有任何作用,你可以放心地忽略它。我从一些样本中捡起它,这有点困在我的答案中。我在以后的编辑中将其遗漏了。
顺便说一句。 phpMyAdmin对空间扩展的支持并不完美,但它有助于查看数据库中的内容。用我附上的这些图片帮助了我。