29

我正在使用 SQL Server 2008 空间数据类型。我有一个表,所有状态(作为多边形)作为数据类型 GEOMETRY。现在我想检查一个点的坐标(纬度、经度)作为数据类型 GEOGRAPHY 是否在该州内。

我找不到任何使用新空间数据类型的示例。目前,我有一个多年前实施的解决方法,但它有一些缺点。

我有 SQL Server 2008 和 2012。如果新版本有一些增强,我也可以开始使用它。

谢谢。

更新 1:

为了更清晰,我添加了一个代码示例。

declare @s geometry  --GeomCol is of this type too.
declare @z geography --GeogCol is of this type too.

select @s = GeomCol
from AllStates
where STATE_ABBR = 'NY'

select @z = GeogCol
from AllZipCodes
where ZipCode = 10101
4

5 回答 5

35

我认为地理方法 STIntersects() 会做你想做的事:

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326);
SET @h = geography::Point(47.653, -122.358, 4326)

SELECT @g.STIntersects(@h)
于 2012-06-15T18:11:06.537 回答
2

如果您无法将存储的多边形的数据类型更改为,GEOGRAPHY那么您可以将输入的纬度和经度转换为GEOMETRY并使用STContainsSTIntersects反对转换后的值。

DECLARE @PointGeography GEOGRAPHY = geography::Point(43.365267, -80.971974, 4326)
DECLARE @PointGeometry GEOMETRY = geometry::STGeomFromWKB(@PointGeography.STAsBinary(), 4326);

SELECT @PolygonGeometry.STContains(@PointGeometry);

朝着相反的方向——试图将GEOMETRY多边形转换为GEOGRPAHY——很容易出错,并且根据我的经验可能会失败。

请注意,如果您尝试GEOMETRY直接从纬度和经度值创建点,那么STContains(or STIntersects) 将不起作用(即在应该匹配时不会给出匹配)。

于 2015-09-18T15:22:58.863 回答
2
declare @g geometry
set @g=geometry::STGeomFromText('POLYGON((-33.229869 -70.891988, -33.251124 -70.476616, -33.703094 -70.508045, -33.693931 -70.891052,-33.229869 -70.891988))',0)

DECLARE @h geometry;

SET @h = geometry::STGeomFromText('POINT(-33.3906300 -70.5725020)', 0);
SELECT @g.STContains(@h);
于 2015-11-10T13:49:31.643 回答
2
  1. 你不应该混合几何和地理。几何适用于平面,地理适用于球体(如地球)。
  2. 您“应该”协调 SRID 以处理此问题。每个 SRID(例如 2913 = NZG2000)描述一个转换关系。每个 SRID 都可用于映射到/从一个统一的球体,这是您从一个球体到另一个球体的方式。
  3. 直到你在两个值上得到一个“相同”的 SRID,许多 .STxXX 函数将返回 NULL(在这两种情况下你可能有默认值 0)
  4. 如果它们不一样,但你假装它们是一样的,你可能会在边缘情况下出错。
  5. 如果您花费一些“预计算”时间,您可以确定所涉及的边界矩形的顶部/左侧和底部/右侧点(并存储它们),并在索引中使用这些值来限制要检查的记录。除非 AT/L < BB/R 和 AB/R > BT/L 它们不能重叠,这意味着在您的 WHERE 中进行简单的 4 AND 数字检查将限制您的 STWithin 检查

这是我在 SRID 2193 中使用的示例。给定点半径 3 公里内以及特定学区内的所有道路

DECLARE @g geometry

SELECT @g = GEO2193 FROM dbo.schoolzones WHERE schoolID = 319

SELECT DD.full_road_name, MIN(convert(int,  dd.address_number)), MAX(convert(int,  dd.address_number))
FROM (

select A.* from dbo.[street-address] A

WHERE (((A.Shape_X - 1566027.50505) * (A.Shape_X - 1566027.50505)) + ((A.Shape_Y - 5181211.81675) * (A.Shape_Y - 5181211.81675))) < 9250000

and a.shape_y > 5181076.1943481788

and a.shape_y < 5185097.2169968253

and a.shape_x < 1568020.2202472512

and a.shape_x > 1562740.328937705

and a.geo2193.STWithin(@g) = 1
) DD
GROUP BY DD.full_road_name
ORDER BY DD.full_road_name
于 2017-10-04T11:23:23.347 回答
1

如果您有表格(例如:SubsriberGeo),其中一列(例如:位置)具有地理点作为值,并且您想从该表格中找到多边形内的所有点,这是一种方法:

 WITH polygons
 AS (SELECT 'p1' id, 
            geography::STGeomFromText('polygon ((-113.754429 52.471834 , 1 5, 5 5, -113.754429 52.471834))', 4326) poly
),
 points
 AS (SELECT [SubscriberId],[Location] as p FROM [DatabaseName].[dbo].[SubscriberGeo])
 SELECT DISTINCT 
        points.SubscriberId, 
        points.p.STAsText() as Location
 FROM polygons
      RIGHT JOIN points ON polygons.poly.STIntersects(points.p) = 1
 WHERE polygons.id IS NOT NULL;
于 2018-12-12T18:23:49.983 回答