2014-02-10 34 views
5

我精通SQL,但新的使用SQL几何特征。我有什么可能是解决一个非常基本的问题,但我还没有发现任何好的资源网上解释如何使用几何对象。 (Technet是一种学习新事物的糟糕方式......)SQL几何找到的所有点的半径

我有一个笛卡尔飞机上的2d点的集合,我试图找到半径集合内的所有点。

我创建和使用的语法像填充一个表:

更新[观光]将[位置] =几何::点(@X,@Y,0)

(@ X,@ÿ只是x和y的值,0是允许设置的过滤,如果我理解正确

这里所有对象共享一个任意数)我走到哪里出轨......难道我试图建立某种形式的多边形采集和查询使用,或者是有检查多个半径的交叉点无需建立一堆圆形多边形的一些简单的方法是什么?

附录:如果没有人有答案的多个半径的问题,什么是单个半径的解决方案?

UPDATE

下面是一些例子我曾起来,用一个虚构的星数据库,在那里星星都存储在一个XY网格为两点:

选择所有的点在一个盒子:

DECLARE @polygon geometry = geometry::STGeomFromText('POLYGON((' 
+ CAST(@MinX AS VARCHAR(10)) + ' ' + CAST(@MinY AS VARCHAR(10)) + ',' 
+ CAST(@MaxX AS VARCHAR(10)) + ' ' + CAST(@MinY AS VARCHAR(10)) + ', ' 
+ CAST(@MaxX AS VARCHAR(10)) + ' ' + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ CAST(@MinX AS VARCHAR(10)) + ' ' + CAST(@MaxY AS VARCHAR(10)) + ',' 
+ 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 

使用这种模式,你可以做各种有趣的事情,如 定义多个多边形:

WHERE @polygon1.STContains([Star].[Location]) = 1 
OR @polygon2.STContains([Star].[Location]) = 1 
OR @polygon3.STContains([Star].[Location]) = 1 

或检查距离:

WHERE [Star].[Location].STDistance(@polygon1) < @SomeDistance 

样品插入语句

INSERT [Star] 
(
    [Name], 
    [StarTypeId], 
    [Location], 
) 
VALUES 
(
    @GameId, 
    @Name, 
    @StarTypeId, 
    GEOMETRY::Point(@LocationX, @LocationY, 0), 
) 

回答

9

这是一个令人难以置信的迟到答案,但也许我可以解决一些问题。您引用的“设置”号码是空间参考标识符或SRID。对于经纬度计算,您应该考虑将其设置为4326,这将确保仪表用作度量单位。您还应该考虑切换到SqlGeography而不是SqlGeometry,但现在我们将继续使用SqlGeometry。要批量设置SRID,您可以更新表如下:

UPDATE [YourTable] SET [SpatialColumn] = GEOMETRY.STPointFromText([SpatialColumn].STAsText(), 4326); 

对于单个半径,你需要创建一个半径为空间对象。例如:

DECLARE @radiusInMeters FLOAT = 1000; -- Set to a number in meters 
DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326).STBuffer(@radiusInMeters); 

STBuffer()获取空间点并从中创建一个圆(现在是Polygon类型)。然后,您可以查询您的数据设置如下:

SELECT * FROM [YourTable] WHERE [SpatialColumn].STIntersects(@radius); 

上面现在将使用您在查询计划的[SpatialColumn]创建的所有空间索引。

还有一个更简单的选项,它可以工作(并且仍然使用空间索引)。 STDistance方法允许您执行以下操作:

DECLARE @radius GEOMETRY = GEOMETRY::Point(@x, @y, 4326); 
DECLARE @distance FLOAT = 1000; -- A distance in metres 
SELECT * FROM [YourTable] WHERE [SpatialColumn].STDistance(@radius) <= @distance; 

最后,使用半径集合。你有几个选择。首先是运行上面依次对每个半径,但我会考虑以下做它作为一个:

DECLARE #radiiCollection TABLE 
(
    [RadiusInMetres] FLOAT, 
    [Radius] GEOMETRY 
) 

INSERT INTO #radiiCollection ([RadiusInMetres], [Radius]) VALUES (1000, GEOMETRY::Point(@xValue, @yValue, 4326).STBuffer(1000)); 
-- Repeat for other radii 

SELECT 
    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%肯定它只是有少量的调整是可能的。选择最小半径距离的理想是,如果多个半径来自单个位置,如果一个点位于第一个半径内,它自然会在所有其他半径内。因此,您将复制记录,但通过分组然后选择最小值,您只能得到一个(也是最接近的)。

希望它有帮助,虽然在你问这个问题后4周。对不起,我没有看到它更快,如果只有一个空间标签的问题!

+1

有趣的第二个解决方案,我需要玩一点,然后想一想。两个小点:我非常肯定,除非你在曲面上工作,否则你不想使用GEOGRAPHY 4326,这是一个非欧几里德曲面。这是一个平坦的空间问题,所以使用GEOMETRY可能是正确的选择。其次,在你的示例中,你建议使用一个sql临时表,当使用一个表变量会更好(更快)。临时表写入磁盘,表中的变量存储在内存中。 – MadTigger

+0

@MadTigger我无法就使用表变量达成一致,但如果我诚实地说,我没有花时间去优化,更多的理论可以帮助你,因为你已经有4个星期了解决了它! :-)再次原谅4326的假设,如果你正在研究平坦空间问题,那么你完全可以不使用4326并使用几何。我只是习惯于人们使用几何来解决实际的“地球”问题,因为他们应该使用地理,而且你的问题在这个问题上还不清楚。假设习惯是我应该踢的一个习惯。 –

-1

当然,这是可能的。

DIM @Center AS Location 
-- Initialize the location here, you probably know better how to do that than I. 
Dim @Radius AS Decimal(10, 2) 
SELECT * from pointTable WHERE sqrt(square(@Center.STX-Location.STX)+square(@Center.STX-Location.STX)) > @Radius 

然后,您可以堆上一堆半径和XY点成样子像一个表变量:

Dim @MyCircleTable AS Table(Geometry Circle) 
INSERT INTO @MyCircleTable (.........) 

注:我没有把这个where子句中应该是这样的个人通过编译器,但这是一个工作解决方案的基石。

其他选项看起来在这里: http://technet.microsoft.com/en-us/library/bb933904.aspx

而且这里有看似工作语法的演示: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/6e1d7af4-ecc2-4d82-b069-f2517c3276c2/slow-spatial-predicates-stcontains-stintersects-stwithin-?forum=sqlspatial

的第二个职位意味着语法:

SELECT Distinct pointTable.* from pointTable pt, circletable crcs 
WHERE crcs.geom.STContains(b.Location) = 1 
+0

这就是如果你打算使用基本的SQL数据类型,你会怎么做。但是,我在询问有关使用SQL几何对象的具体情况,因为它们使用四叉树或其他空间索引。如果你想搜索一个有几十万分的数据库,那么使用空间分区的对象根本就没有问题,你的解决方案将完全分崩离析。随着我添加额外的radiai,它会变得更糟糕,因为我将不得不检查每个半径的db中每个点的距离。感谢您的尝试,尽管 – MadTigger

+0

服务器并不神奇,无论如何您都将进行大量的计算。如果数据仓库或计算字段是巨大的表,并且服务器负载/正常运行时间非常重要,您将需要数据仓库或计算字段。也就是说,解决方案更新为包含SQL本机可能性。 –

+1

这是不正确的。空间索引(BSP树,四叉树等)的目的是避免必须通过将搜索空间快速修剪到相关数据来完成所有的数学运算。空间索引,如果使用得当,速度非常快。据说,你发现的链接非常有帮助。我将写一篇关于未来读者如何做到这一点的大纲。感谢您的帮助。 – MadTigger