简体   繁体   English

SQL Server 2008 空间:在多边形中找到一个点

[英]SQL Server 2008 Spatial: find a point in polygon

I am using SQL Server 2008 spatial data types.我正在使用 SQL Server 2008 空间数据类型。 I have a table with all States (as polygons) as data type GEOMETRY.我有一个表,其中包含所有状态(作为多边形)作为数据类型 GEOMETRY。 Now I want to check if a point's coordinates (latitudes, longitudes) as data type GEOGRAPHY, is inside that State or not.现在我想检查一个点的坐标(纬度、经度)作为数据类型 GEOGRAPHY 是否在该州内。

I could not find any example using the new spatial data types.我找不到任何使用新空间数据类型的示例。 Currently, I have a workaround which was implemented many years ago, but it has some drawbacks.目前,我有一个多年前实施的解决方法,但它有一些缺点。

I've both SQL Server 2008 and 2012. If the new version has some enhancements, I can start working in it too.我有 SQL Server 2008 和 2012。如果新版本有一些改进,我也可以开始使用它。

Thanks.谢谢。

UPDATE 1:更新1:

I am adding a code sample for a bit more clarity.我正在添加一个代码示例,以便更加清晰。

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

I think the geography method STIntersects() will do what you want:我认为地理方法 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)

If you cannot change the data-type for the stored polygons to GEOGRAPHY then you can convert the input latitude and longitude to GEOMETRY and use the STContains or STIntersects against the converted value.如果您无法将存储多边形的数据类型更改为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);

Going the opposite direction -- trying to convert the GEOMETRY polygons to GEOGRPAHY -- is error-prone and likely to fail from my experience.相反的方向——试图将GEOMETRY多边形转换为GEOGRPAHY很容易出错,并且根据我的经验可能会失败。

And note that if you try to create the GEOMETRY point directly from the latitude and longitude values then the STContains (or STIntersects ) won't work (ie won't give a match when they should).请注意,如果您尝试直接从纬度和经度值创建GEOMETRY点,那么STContains (或STIntersects )将不起作用(即,在应该匹配时不会提供匹配项)。

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);
  1. You shouldn't be mixing Geometry and Geography.你不应该混合几何和地理。 Geometry is for FLAT PLANES, Geography is for SPHEROIDS (like Earth).几何适用于平面,地理适用于球体(如地球)。
  2. You "should" reconcile the SRIDs to deal with this.您“应该”协调 SRID 来处理这个问题。 Each SRID (eg 2913 = NZG2000) describes a transformation relationship.每个 SRID(例如 2913 = NZG2000)描述一个转换关系。 Each SRID can be used to map to/from a uniform sphere, which is how you get from one to another.每个 SRID 都可以用来映射到/从一个统一的球体,这是你从一个球体到另一个球体的方式。
  3. Until you get to a "same" SRID on both values, many of the .STxXX functions will return NULL (you might have default 0 in both cases)直到您在两个值上都获得“相同”的 SRID,许多 .STxXX 函数将返回 NULL(在这两种情况下您可能都有默认值 0)
  4. If they are not the same but you pretend they are, you may have errors on the edge cases.如果它们不一样,但你假装它们是一样的,你可能会在边缘情况下出错。
  5. If you spend some "precalc" time, you can determine the top/left and bottom/right points for the bounding rects involved (and store them), and use those values in indexes to limit the records to check.如果您花费一些“预计算”时间,您可以确定所涉及的边界矩形的上/左和下/右点(并存储它们),并在索引中使用这些值来限制要检查的记录。 Unless AT/L < BB/R and AB/R > BT/L they cannot overlap, which means a simple 4 AND numeric check in your WHERE will limit your STWithin checks除非 AT/L < BB/R 和 AB/R > BT/L 它们不能重叠,这意味着您的 WHERE 中的简单 4 AND 数字检查将限制您的 STWithin 检查

Here's an example I used in SRID 2193. All roads within a 3km radius of a given point, and inside a specific school zone这是我在 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

In case you have table (example: SubsriberGeo) where one of the columns (example: Location) has geography Points as values and you'd like to find all Points from that table that are inside polygon here is a way to do it:如果您有表(例如: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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM