MySQL - 选择矩形内的所有几何

时间:2014-08-23 10:25:58

标签: mysql sql geospatial

我有一个带有以下结构的表AREAGEOMETRY:

+-----------------+----------+------+-----+---------+-------+
| Field           | Type     | Null | Key | Default | Extra |
+-----------------+----------+------+-----+---------+-------+
| AREAGEOMETRY_ID | int(11)  | NO   | PRI | NULL    |       |
| AreaManagerId   | int(11)  | YES  |     | NULL    |       |
| AreaId          | text     | YES  |     | NULL    |       |
| EndDateArea     | datetime | YES  |     | NULL    |       |
| StartDateArea   | datetime | YES  |     | NULL    |       |
| AreaGeometryTxt | text     | YES  |     | NULL    |       |
+-----------------+----------+------+-----+---------+-------+

它包含停车区的数据。现在我要做的是选择边界框内的所有行。

边界框可能如下:

LatLngBounds{southwest=lat/lng: (52.35631327204287,4.881156384944916), northeast=lat/lng: (52.38006384519922,4.913054890930653)}

我想出了以下查询:

SELECT * FROM AREAGEOMETRY WHERE ST_OVERLAPS(GeomFromText(AreaGeometryTxt), GeomFromText('LINESTRING(52.35631327204287 4.881156384944916, 52.38006384519922 4.881156384944916, 52.38006384519922 4.913054890930653, 52.35631327204287 4.913054890930653, 52.35631327204287 4.881156384944916)'))

然而它似乎返回表中的所有行,我不知道这里出了什么问题。 也许有人可以指出我正确的方向。

编辑:

例如,它返回此行:

# AREAGEOMETRY_ID, AreaManagerId, AreaId, EndDateArea, StartDateArea, AreaGeometryTxt
493, 299, 8721, 0000-00-00 00:00:00, 0000-00-00 00:00:00, POLYGON ((6.071624141 51.927465383, 6.071167939 51.927755315, 6.073816653 51.928513734, 6.07434586 51.928376592, 6.072239751 51.927748706, 6.072269225 51.927414931, 6.071624141 51.927465383))

不应该这样。

EDIT2: 一些可能的视口及其结果:

视口1:

LatLngBounds{southwest=lat/lng: (52.367693923958065,6.981273405253887), northeast=lat/lng: (52.3812037840295,6.99942022562027)}

查询:

SELECT * FROM AREAGEOMETRY WHERE ST_CONTAINS(GeomFromText('LINESTRING(52.367693923958065 6.981273405253887, 52.3812037840295 6.981273405253887, 52.3812037840295 6.99942022562027, 52.367693923958065 6.99942022562027, 52.367693923958065 6.981273405253887)'), GeomFromText(AreaGeometryTxt));

预期结果:返回0行

实际结果:返回0行

视口2:

LatLngBounds{southwest=lat/lng: (52.20765248996001,6.881230026483536), northeast=lat/lng: (52.23028692988024,6.911527253687382)}

查询:

SELECT * FROM AREAGEOMETRY WHERE ST_CONTAINS(GeomFromText('LINESTRING(52.20765248996001 6.881230026483536, 52.23028692988024 6.881230026483536, 52.23028692988024 6.911527253687382, 52.20765248996001 6.911527253687382, 52.20765248996001 6.881230026483536)'), GeomFromText(AreaGeometryTxt));

预期结果:返回约25行

实际结果:返回0行

另一个查询相同的视口:

SELECT * FROM AREAGEOMETRY WHERE ST_Overlaps(GeomFromText('LINESTRING(52.20765248996001 6.881230026483536, 52.23028692988024 6.881230026483536, 52.23028692988024 6.911527253687382, 52.20765248996001 6.911527253687382, 52.20765248996001 6.881230026483536)'), GeomFromText(AreaGeometryTxt));

预期结果:返回约25行

实际结果:返回1000行(受MySQL Workbench限制)

编辑3: 以下查询返回我想要的内容:

SELECT * FROM AREAGEOMETRY WHERE ST_Intersects(GeomFromText('Polygon((6.881230026483536 52.20765248996001, 6.881230026483536 52.23028692988024, 6.911527253687382 52.20765248996001, 6.881230026483536 52.20765248996001))'), GeomFromText(AreaGeometryTxt));

好像我混合了Lat / Lng并且参数的顺序错误。

1 个答案:

答案 0 :(得分:2)

您应该使用包含或相交,具体取决于您是否要包含边框上的对象,或者是否要完全包含。 但是,你的主要问题是你的几何形状是错误的,如果你看Contains documentation你会看到它是包含(g1,g2)如果g1包含g2则返回1,所以你会想要把你的边界框放在第一位。

SELECT * FROM AREAGEOMETRY WHERE ST_CONTAINS(ST_GeomFromText('LINESTRING(52.35631327204287 4.881156384944916, 52.38006384519922 4.881156384944916, 52.38006384519922 4.913054890930653, 52.35631327204287 4.913054890930653, 52.35631327204287 4.881156384944916)'), ST_GeomFromText(AreaGeometryTxt));

您可能还需要考虑将AreaGeometryTxt存储为几何体而不是文本,因为这会给您带来两个好处:

  1. 然后,您可以在其上放置spatial index,这会随着表格大小的增长而提高查询时间。

  2. 您将避免每个查询的GeomFromText转换开销,与第1点一起,将阻止每次执行全表扫描。

  3. 编辑:我运行了以下查询,使用了您不应该返回的行以及原始的lat / lon边界框:

    select ST_Overlaps(ST_GeomFromText('POLYGON ((6.071624141 51.927465383, 6.071167939 51.927755315, 6.073816653 51.928513734, 6.07434586 51.928376592, 6.072239751 51.927748706, 6.072269225 51.927414931, 6.071624141 51.927465383))'),
                    ST_GeomFromText('POLYGON ((4.881156384944916 52.35631327204287, 4.881156384944916 52.38006384519922, 4.913054890930653 52.38006384519922, 4.913054890930653 52.35631327204287, 4.881156384944916 52.35631327204287))'));
    

    此查询为overlapsintersectscontains返回0(false)。