回答

收藏

SQL几何搜索半径中的所有点

技术问答 技术问答 182 人阅读 | 0 人回复 | 2023-09-14

我精通SQL,但是对使用SQL几何功能很奇怪。我可能要解决一个非常基本的问题,但我没有在网上找到任何好的资源来解释如何使用几何对象。(Technet学习新事物的坏方法…)
. N* I2 t/ X1 @: X6 w1 p我在笛卡尔平面上有2个d点的集合,我试图在半径集合中找到所有点。0 [# F4 `4 E1 c! X) L7 ~+ G5 W$ t
我用以下语法创建并填写了一个表:
0 Y8 `, d0 ~; X. N5 }设置[位置]= geometry :: Point(@X,@Y,0)9 O) b$ q: f6 Q) @: _# ]1 |3 S
(@ X,@ Y只是x和y值,0是所有对象共享的任何数字,如果我理解正确,它允许过滤)3 |( D6 w! H! T9 ]
这是我脱离困境的地方…我是否试图在没有一堆圆形多边形的情况下建立一个多边形集合并使用它进行查询,或者是否有一些简单的方法来检查多个半径的交?
+ G% K- Z6 [! T6 z- x4 }( p附录:如果没有人回答多半径问题,单半径解决方案是什么?
/ X- C& t* l, L: F更新2 Y% x" W6 x+ e9 Z; X" h! m
这是我使用虚构恒星数据库处理的一些例子,其中恒星存储在xy以网格为点:
& ^; R  X7 o% e7 U选择框中的所有点:' U7 d- `; r; \  j
DECLARE @polygon geometry = geometry::STGeomFromText('POLYGON(   CAST(@MinX AS VARCHAR(10)   CAST(@MinY AS VARCHAR   CAST(@MaxX AS VARCHAR(10)   CAST(@MinY AS VARCHAR   CAST(@MaxX AS VARCHAR(10)   CAST(@MaxY AS VARCHAR   CAST(@MinX AS VARCHAR(10)   CAST(@MaxY AS VARCHAR   CAST(@MinX AS VARCHAR(10)   CAST(@MinY AS VARCHAR(10)0);SELECT  [Star].[Name]           AS [StarName],       [Star].[StarTypeId]     AS [StarTypeId],       FROM    [Star]WHERE   @polygon.STContains([Star].[Location]) = 1在这种模式下,你可以做各种有趣的事情,比如定义多多边形:
! \. v9 h2 e5 ^  U3 s- F# ?WHERE   @polygon1.STContains([Star].[Location]) = 1OR @polygon2.STContains([Star].[Location]) = 1OR @polygon3.STContains([Star].[Location]) = 1或检查距离:. \+ E# y" r) v' ^6 G( g; R# q
WHERE [Star].[Location].STDistance(@polygon1) 样本插入句子
9 S8 ~' [$ S8 s- i  J, L0 FINSERT [Star](    [Name],   [StarTypeId],   [Location],)VALUES(    @GameId,   @Name,   @StarTypeId,   GEOMETRY:oint(@LocationX,@LocationY,),                  $ K& p9 Z2 ?5 L% Z
    解决方案:                                                               
/ o8 |* B1 F) g  j1 {                                                                这是一个不可思议的迟到答案,但也许我可以解释一个解决方案。您引用的设置数字是空间参考标志符或SRID。对于纬度/经度计算,应考虑将此值设置为4326,以确保仪器用作测量单位。您还应该考虑切换到SqlGeography而不是SqlGeometry,但我们现在将继续使用它SqlGeometry。要批量设置SRID,您可以通过以下方式更新表格:
) \+ K* d  Y/ U7 m" ~: OUPDATE [YourTable] SET [SpatialColumn] = GEOMETRY.STPointFromText([SpatialColumn].STAsText(),4326);对于单个半径,您需要创建一个半径作为空间对象。
. S2 ^" {8 Z; K: J0 y0 j8 }. bDECLARE @radiusInMeters FLOAT = 1000; -- Set to a number in metersDECLARE @radius GEOMETRY = GEOMETRY:oint(@x,@y,4326).STBuffer(@radiusInMeters);STBuffer()获得空间点并从中创建一个圆(现在是Polygon类型)。您可以查询以下数据集:
) j- e5 l7 w. Z& [  ^$ h; S: s' Q' bSELECT * FROM [YourTable] WHERE [SpatialColumn].STIntersects(@radius);上述代码将在其查询计划中使用[SpatialColumn]创建的任何空间索引。2 B; ^$ `1 [% S2 n1 t* I
还有一个更简单的选项可以工作(并且仍然使用空间索引)。STDistance该方法允许您执行以下操作:
3 S% x; `- v5 l* H0 E- P! g9 lDECLARE @radius GEOMETRY = GEOMETRY:oint(@x,@y,4326);DECLARE @distance FLOAT = 1000; -- A distance in metres   SELECT * FROM [YourTable] WHERE [SpatialColumn].STDistance(@radius) 最后,使用半径集合。您有几种选择。一是依次操作上述操作,但我将考虑以下内容:: d( u* g9 F/ h8 [# y
DECLARE #radiiCollection TABLE(    [RadiusInMetres] FLOAT,   [Radius] GEOMETRY)INSERT INTO #radiiCollection ([RadiusInMetres],[Radius]) VALUES (1000,GEOMETRY:oint(@xValue,@yValue,4326).STBuffer(1000));-- Repeat for other radiiSELECT    X.[Id],   MIN(R.[RadiusInMetres]) AS [WithinRadiusDistance]FROM    [YourTable] X    JOIN    #radiiCollection RC ON RC.[Radius].STIntersects(X.[SpatialColumn])GROUP BY    X.[IdColumn],   R.[RadiusInMetres]DROP TABLE @radiiCollection;最后一个没有测试,但我有99%可以肯定的是,它就在那里,少量的调整。选择中最小半径距离的理想方法是,如果多个半径来自单个位置,如果一个点在第一个半径内,它自然会在所有其他半径内。因此,您将复制记录,但通过分组选择最小值,您只会得到一个(最接近)。; `. \8 r* J: g$ z8 K0 A
我希望它能帮助你,尽管在你提出问题4周后。对不起,如果只有一个空间标签提问,我不会很快看到它!!!
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则