使用 SQL 空间数据类型(STIntersect/STContains 等)返回 lat long 所在的多边形

Posted

技术标签:

【中文标题】使用 SQL 空间数据类型(STIntersect/STContains 等)返回 lat long 所在的多边形【英文标题】:Return the polygon that lat long resides within using SQL Spatial Data types (STIntersect/STContains etc) 【发布时间】:2018-09-23 22:13:55 【问题描述】:

我已经研究了两天,找不到任何适合我的东西,这可能是我的数据库设计,但我认为它的设计没问题。

我有一个名为“post_codes_new”的表,它包含以下列;

id (int)
post_code (varchar, example: "0612")
post_code_name (varchar, example: "Henderson")
latlongs (geography data type - forming a polygon)

我试图做的是使用 lat/long 点查询此表,以返回包含该 lat/long 的任何 post_codes 记录(lat/long 落在其边界内的任何记录)。

这是我一直在做的事情;

DECLARE @point geography;
SET @point = geography::STGeomFromText('POINT(174.94280000 -36.75000000)',4326)
select post_code
from dbo.post_codes_new
WHERE latlongs.MakeValid().STContains(@point) = 1;

无论我在此处输入什么纬度/经度点,我的查询都会返回该表中 1081 条记录中的 931 条,并且需要 22 秒......它应该只返回一条记录。当然,我希望性能更好。

我正在努力实现这一目标;

['PSEUDO-CODE' QUERY OF WHAT I'D LIKE TO ACHIEVE]
SELECT post_codes.* FROM post_codes WHERE latlongs.STIntersects(myLatLongPoint) = 1 

我看过的例子(在这个网站和其他地方)似乎都适用于查询中定义的多边形(即,点在查询正文中明确列出)。我见过一些查看包含多边形边界的记录,但没有一个对我有用。

谢谢。

【问题讨论】:

我想试试这个 - 你有我可以用来实验的样本数据吗? 一些通常会绊倒人们的事情。多边形的方向(即顺时针或逆时针)很重要。使用相同的边界,以一种方式定义多边形将定义您期望的区域;以另一种方式定义它将使用多边形定义的孔指定整个地球。所以,如果你的多边形是这样定义的,那就可以解释为什么你得到的交叉点比你预期的要多。另一个是:您使用的是空间索引吗?对于 1000 行,这应该相对较快(假设硬件不错等)。 抱歉,我很晚才回复 Tomc 和 Ben Thul。谢谢你的回复。我会尝试反转,因为我发现了一些关于顺时针/逆时针等的信息。如果这不能解决我遇到的问题,我会放置一些示例代码供您查看。请记住,其中一个多边形有超过 44,000 个点(这是新西兰一个复杂的沿海邮政编码区)。干杯。 顺便说一句,如果我从数据库中取出我的一个邮政编码并将其添加到与查询内联的 STGeomFromText() 函数中,它会按预期工作。只有当我直接从数据库字段中查询它时它才会停止工作(这表明问题可能存在于字段数据中)。我在导入该数据时没有遇到任何错误,并且在将其放入时没有将其反转,所以我假设它没问题......我可能错了。 我看到了这个(关于 STUnion)gis.stackexchange.com/questions/66671/… 但我从来没有出现过那个半球错误。我像这样尝试了 STUnion -> [code] DECLARE @g geography; SET @g = geography::STGeomFromText('POINT(174.60000000 -39.00000000)',4326) select * from dbo.post_codes_new WHERE latlong.MakeValid().STUnion(latlong.MakeValid()).STIntersects(@g) = 1; [/code] 不过没区别,我的1081的931条记录还是被退回了。 【参考方案1】:

非常感谢@BenThul 和@TomC。事实证明,确实,我的点是按顺时针方向输入的,它包裹了“世界其他地方,不包括你的多边形”并将其创建为一个多边形区域 - 因此在我的查询中返回了 1081 条记录中的 931 条。

所以我取了我现有的多边形点(我已经存储为 nvarchar(MAX) 字符串,在我的地理列旁边)并将它们反转,然后用这些反转的值重写我的地理列。然后,我对一些已知的地址/邮政编码组合进行了查询,并且效果很好。正如预期的那样,每个查询返回一个邮政编码。太棒了!

查询运行需要(始终)16 秒,但我将把这个速度问题作为一个单独的问题来处理。

谢谢你们。

【讨论】:

以上是关于使用 SQL 空间数据类型(STIntersect/STContains 等)返回 lat long 所在的多边形的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SQL 查询将值传递给具有空间/地理数据类型的存储过程

将 geoJson 数据转换为 sql server 空间数据类型(GIS)

SQL-数据类型占空间大小

处理 SQL Server 2012 表中的空间数据类型

在SQL数据类型中,Unicode数据类型和非Unicode数据类型具体有啥区别?

SQL server Varchar(max) 和占用的空间