This post covers the following methods: STDisjoint, **STIntersects**, Filter, **STTouches**, **STWithin**, **STContains**, **STOverlaps**, STCrosses, STRelate, & **STEquals**

One day these examples may find their way to Books Online. For now they can live here.

## Overview of Conditional Methods

You will find that these Methods exceptionally handy to find or filter out similar spatial shapes. They are extremely efficient when a suitable spatial index exists.

I'm not saying these methods can ONLY be used in a WHERE clause. It is often handy to combine them with a CASE clause in the select list. However I wanted to group sets of Methods together & this seemed an appropriate name.

These methods Return a boolean: 1 (true) or 0 (false).

**Tip: **They take advantage of Spatial Index to retrieve relevant rows quickly. Especially if you ask for what you __want,__ so searching for Equality works well, but filtering on not equals, often means the index will not help you. Most methods have a opposite ie: STDisjoint is the opposite of STIntersects. So instead of using "not equals" change to the reciprocal method.

**The following code sample** lets you explore the GIS Methods. Just Cut n Paste into SQL Server Management Studio (SSMS) 2008 (or higher).

**Note 1**: If your data has POINTs then the SSMS Spatial viewer disables the ability to display labels. While this is nice if you have a few polygons with names, covers in a lot of points, is it inconvenient here. So comment out the last 3 Union Alls if you want show the labels of your shapes & lines. You can still hover over them to see ToolTip labels on points.

**Note 2**: Usually you would not have the @S0 shape in the set of shapes you are querying. So sometimes @S0 is in the results where normally it wouldn’t be. I've left it in so you can see the relationship with it & the object you are comparing against it.

-- ===< Samples: TSQL Spatial Conditional Methods as a filter >=== DECLARE @s0 AS GEOMETRY = 'POLYGON((4 4, 7 4, 7 7, 4 7 ,4 4))' -- Main Shape DECLARE @s1 AS GEOMETRY = 'POLYGON((5 4.2, 6 4.2, 6 5, 5 5, 5 4.2))' -- Inside Shape DECLARE @s2 AS GEOMETRY = 'POLYGON((5 3, 6 3, 6 4, 5 4, 5 3))' -- Part Edge in Common DECLARE @s3 AS GEOMETRY = 'POLYGON((7.2 4, 8 4, 8 5, 7.2 5, 7.2 4))' -- Outside Shape DECLARE @t1 AS GEOMETRY = 'POLYGON((3 4, 4 4, 4 3, 3 4))' -- 2 Corners in Common DECLARE @t2 AS GEOMETRY = 'POLYGON((3 5, 4 5.5, 3 6, 3 5))' -- Corner on an Edge DECLARE @t3 AS GEOMETRY = 'POLYGON((6.5 5, 7.5 5.5, 6.5 6, 6.5 5))' -- Overlap DECLARE @L1 AS GEOMETRY = 'LINESTRING(5 6.5, 6.5 6.5)' -- Line in Shape DECLARE @L2 AS GEOMETRY = 'LINESTRING(4.5 3, 4.5 7.5)' -- Line Thru Shape DECLARE @L3 AS GEOMETRY = 'LINESTRING(3 6.5, 4.2 6.5)' -- Line cross Edge of Shape DECLARE @P1 AS GEOMETRY = 'POINT(6.5 4.5)' -- Point in Shape DECLARE @P2 AS GEOMETRY = 'POINT(4 5)' -- Point on Edge DECLARE @P3 AS GEOMETRY = 'POINT(6.5 3.5)' -- Point off Shape SELECT * -- Make all variables appear as the rows of one table FROM ( SELECT @s0 AS 'Geo', 'S0' as 'Labels' UNION ALL SELECT @s1, 'S1' UNION ALL SELECT @s2, 'S2' UNION ALL SELECT @s3, 'S3' UNION ALL SELECT @t1, 'T1' UNION ALL SELECT @t2, 'T2' UNION ALL SELECT @T3, 'T3' UNION ALL SELECT @L1, 'L1' UNION ALL SELECT @L2, 'L2' UNION ALL SELECT @L3, 'L3' -- As Labels don't display in SSMS when you have Points in output. -- Either Comment out the next 3 lines if you want to see the labels in SSMS. -- or put a buffer around them so they display as polygons.

UNION ALL SELECT @P1.STBuffer(0.1), 'P1' UNION ALL SELECT @P2.STBuffer(0.1), 'P2' UNION ALL SELECT @P3.STBuffer(0.1), 'P3' ) AS A --Uncomment ONE of the lines below to test the effect of each different where clause -- WHERE A.Geo.STTouches(@s0) = 1 -- WHERE A.Geo.STWithin(@s0) = 1 -- WHERE A.Geo.STCrosses(@s0) = 1 -- WHERE A.Geo.STContains(@S1) = 1 -- WHERE A.Geo.STOverlaps(@s0) = 1 -- WHERE A.Geo.STIntersects(@s0) = 1 -- WHERE A.Geo.STDisjoint(@s0) = 1

When you run the code all the objects display as shown in this diagram.

Use this as a baseline when we look at the results of the different filters below.

## Method .STDisjoint()

- Spatial Objects
**DO NOT**touch each other. - Works with both
**Geometry**&**Geography**objects - Opposite method of .STIntersects & .Filter Methods.

Example use: Show all customers who live outside our standard delivery area

WHERE A.Geo.STDisjoint(@s0) = 1

Yellow highlights all objects which are Disjoint from Shape S0

## Method .STIntersects()

- Spatial Objects
**DO**touch each other. - Works with both
**Geometry**&**Geography**objects - Opposite of .STDisjoint Method.
- Similar to .Filter
- To use spatial index search on WHERE geo1.STIntersects ( geo2 ) = 1

Example use: List cancer patients who live within 1km of a high tension power line.

WHERE A.Geo.STIntersects(@s0) = 1

Yellow highlights all objects which Intersect with Shape S0

## Method .Filter()

- Spatial Objects
**DO**touch each other. - Works with both
**Geometry**&**Geography**objects - Opposite of .STDisjoint Method.
- Similar to .STIntersects() but :-
- Less accurate sometimes returns false positive results. Eg: Says they intersect when they do not.
- often much faster if a relevant spatial index exists.

- So, Great for getting results to display not so good for accurate analysis. Eg: Find all shapes in this rectangle (my window). If you get back a few extra shapes that are outside the rectangle then they will be clipped when you try to draw them outside the window.

Example use: Show cancer patients who live within 1km of a high tension power line.

-- ===< Sample: Using FILTER to rapidly get relevant results >==== USE someDB -- This will give you an error, reminding you not to create it in Master :-) go -- ==< Create a Table with a spatial Index >=== CREATE TABLE dbo.GeoTable (id INT PRIMARY KEY, geom GEOGRAPHY); INSERT INTO GeoTable VALUES (0, GEOGRAPHY::Point(45, -120, 4326)), (1, GEOGRAPHY::Point(45, -120.1, 4326)), (2, GEOGRAPHY::Point(45, -120.2, 4326)), (3, GEOGRAPHY::Point(45, -120.3, 4326)), (4, GEOGRAPHY::Point(45, -120.4, 4326)); CREATE SPATIAL INDEX GeoTable_idx ON dbo.GeoTable(geom); -- ==< Example: The Filter Query >== -- Remember to look in the SSMS Spatial Results tab for see the relationships here

SELECT id FROM dbo.GeoTable WHERE geom.Filter(GEOGRAPHY::Parse('POLYGON((-120.2 44.9, -119.9 44.9, -119.9 45.1, -120.1 45.1, -120.2 44.9))')) = 1; -- Show the Geo Data -- SELECT geom.STBuffer(2000) AS Geom, Cast(id AS VARCHAR(4)) AS 'Labels' FROM dbo.GeoTable UNION ALL SELECT GEOGRAPHY::Parse('POLYGON((-120.2 44.9, -119.9 44.9, -119.9 45.1, -120.1 45.1, -120.2 44.9))') AS SD, 'Poly'; go DROP TABLE dbo.GeoTable go

## Method .STTouches(Geometry object)

- The edges of the Spatial Objects
**touch but their interiors don’t overlap**each other. For points this means they are on the border of an object. - Works with
**Geometry**objects only. It is not a method of Geography Objects. - To use spatial index search on WHERE geo1.STTouches ( geo2 ) = 1

Example use: List all suburbs next to Suburb X. Part of a larger query to find homes for sale in or near this suburb.

WHERE A.Geo.STTouches(@s0) = 1

Yellow highlights all objects which touch Shape S0

## Method .STWithin()

- This Spatial Object is completely contained within another.
- Works with
**Geometry**objects only. It is not a method of Geography Objects. - Sister method of .
**STContains** - To use spatial index search on WHERE geo1.STWithin ( geo2 ) = 1

Example use: Find all homes within 3km of the Bush Fire zone. Would also need

STBufferto expand the Bush Fire Zone shape by 3km.

WHERE A.Geo.STWithin(@s0) = 1

Yellow highlights all objects which are completely inside Shape S0

## Method .STContains()

This Spatial Object is completely surrounded by another. Works with Geometryobjects only. It is not a method of Geography Objects.Sister method of . STWithin, but asks the question from the other perspective.To use spatial index search on WHERE geo1.STContains ( geo2 ) = 1

Example use: Find the polygon (postcode) that the mouse cursor is currently hovering over. You'd need to convert the mouse value into a point, & see what shape contains that point.

I've combined the display of 3 queries into one diagram. ie:-

WHEREL1.STContains(@S0) = 1

ORS1.STContains(@S0) = 1

ORP1.STContains(@S0) = 1

Yellow highlights all objects which are contained by Shape S0Note: This query is different, all others use the Geo Column & compare it to the shape S0. These queries use the STContains method on the shape we are interested in & compare it to shape S0

## Method .STOverlaps()

True when this Shapes partly lie on other shapes OR lines cross. Works with Geometryobjects only. It is not a method of Geography Objects.Sister method of . STCrosses, but only works when objects are the same type: ie Shapes with shapes, Lines with lines.To use spatial index search on WHERE geo1.STOverlaps ( geo2 ) = 1

Example use: Show the Sales Territories where it is not clear who "owns" a new customer.

WHERE A.Geo.STOverlaps(@s0) = 1

Yellow highlights all Polygons which lie over the border of Shape S0

## Method .STCrosses()

True when a Line overlaps a Polygon OR A Point lies on a line. ie: Something of a lesser Dimension (1D - Line or 0D - Point) Works with Geometryobjects only. It is not a method of Geography Objects.Sister method of . STCrosses, but only works when objects are different dimensions. So

Why not T3?Because the intersection is still a 2D Object, use STOverlaps() for this.

WHERE A.Geo.STCrosses(@s0) = 1

Yellow highlights all Lines & Points which lie over the border of Shape S0

-- Sample 2: Show a Conditional method being used in a Select list --- -- Also show STCrosses() working with lines & Points DECLARE @L as GEOMETRY = GEOMETRY::STGeomFromText('LINESTRING(1 0, 5 0)',0); DECLARE @Pon as GEOMETRY = GEOMETRY::STGeomFromText('POINT(2 0)',0); DECLARE @Pend as GEOMETRY = GEOMETRY::STGeomFromText('POINT(5 0)',0); DECLARE @Poff as GEOMETRY = GEOMETRY::STGeomFromText('POINT(3 1)',0); -- Test STCrosses SELECT geo, WKT, Labels, CASE @L.STCrosses(geo) WHEN 0 THEN 'STCrosses is FALSE' WHEN 1 THEN 'STCrosses is TRUE' END AS STCrosses FROM ( SELECT @L as geo, @L.ToString() as WKT, 'L1' as 'Labels' UNION ALL SELECT @Pon.STBuffer(0.1), @Pon.ToString(), 'Point on Line' UNION ALL SELECT @Pend.STBuffer(0.1), @Pend.ToString(), 'Point on End of Line' UNION ALL SELECT @Poff.STBuffer(0.1), @Poff.ToString(), 'Point not on Line' ) AS TResults:

WKT

Labels

STCrossesLINESTRING (1 0, 5 0) Line1 STCrosses is FALSE POINT (2 0) Point on Line1 STCrosses is TRUE POINT (5 0) Point on End of Line1 STCrosses is TRUE POINT (3 1) Point not on Line1 STCrosses is FALSE

## Method .STRelate( ,Intersection Matrix)

This Spatial Object has whatever relationship you describe in the Intersection Matrix. Works with Geometryobjects only. It is not a method of Geography Objects.It is a superset of all the other methods described in this blog & easily deserves a post dedicated to it. It could easily replace all the “Conditional methods” in this blog eg: .STDisjoint(), STTouches() etc

As there are already good articles available on the web, I will provide a superficial coverage here, for more detail I suggest you look at the following. ESRI's Developer Help: Understanding Spatial Relations

## What is an Intersection Matrix?

The 2nd Parameter that you provide is an Intersection Matrix.

An Intersection Matrix short for a Dimensionally Extended 9 Intersection Model (DE-9IM). This is a 3 * 3 grid that represents the possible intersections between 2 shapes. Each shape is divided into 3 parts; Interior, Boundary & Exterior & results in a grid below.

1. All possible intersections between 2 shapes; Shape "a" & Shape "b"

Interior (b)Boundary (b)Exterior (b)Interior (a)I(a) ? I(b) I(a) ? B(b) I(a) ? E(b) Boundary (a)B(a) ? I(b) B(a) ? B(b) B(a) ? E(b) Exterior (a)E(a) ? I(b) E(a) ? B(b) E(a) ? E(b)

2. Each of the 9 possible intersections can have one of 6 possible values.

ValueCommentsMaximum DimensionalityT An intersection must exist dim = 0, 1, or 2 F An intersection must not exist dim = -1 * It does not matter if an intersection exists or not dim = -1, 0, 1, or 2 0 An intersection must exist and its maximum dimension must be 0 dim = 0 1 An intersection must exist and its maximum dimension must be 1 dim = 1 2 An intersection must exist and its maximum dimension must be 2 dim = 2

For example, the intersection matrix for theSTWithinmethod would look like:-

b Interior (b)Boundary (b)Exterior (b)Interior (a)T * F a Boundary (a)* * F Exterior (a)* * *

ie: A must be inside B, But A's Interior & Boundary can not be external to B.

This is then mapped to 9 characters representing <top line><Middle><bottom Line>. Which in this case is "T*F**F***".Experiment by changing the value in the code below, or combine it into the main code set at the top of this blog.

-- Create Shapes DECLARE @Main as GEOMETRY = GEOMETRY::STGeomFromText('POLYGON((10 10, 20 20, 10 30, 0 20, 10 10))',0); DECLARE @S_In as GEOMETRY = GEOMETRY::STGeomFromText('POLYGON((4 20, 16 20, 10 26, 4 20))',0); DECLARE @S_On as GEOMETRY = GEOMETRY::STGeomFromText('POLYGON((12 12, 12 18, 18 18, 18 12, 12 12))',0); DECLARE @S_Out as GEOMETRY = GEOMETRY::STGeomFromText('POLYGON((0 10, 8 10, 0 18, 0 10))',0); -- Intersection Matrix DECLARE @Matrix as CHAR(9) = 'T*F**F***' --'FF*FF****' -- Use STRelate in a query -- SELECT geom, Labels, CASE geom.STRelate(@Main,@Matrix) WHEN 0 THEN 'FALSE' WHEN 1 THEN 'TRUE' END AS [STRelate] FROM ( SELECT @Main as geom, 'Main' as 'Labels' UNION ALL SELECT @S_In, 'S_In' UNION ALL SELECT @S_On, 'S_On' UNION ALL SELECT @S_Out, 'S_Out' ) As Tab1;

## Method .STEquals()

- Spatial Objects
**represent the same set of points as each other**. - Works with both
**Geometry**&**Geography**objects - To use spatial index search on WHERE geo1.STEquals ( geo2 ) = 1
- Be careful with this Method it is not as straightforward as you may first think. The following are all considered equal.
- At its most trivial, two polygons may be comprised of the same points but have a different starting point.
- eg: A triangle may have the same 3 points. But if you start at a different point you will have the same triangle but the points will appear in a different order. Clearly that same logic applies to more complex shapes

- A little less obvious. One shape can have more points than the other. So long as the extra points are still on the boundary of the other.
- eg: LineString(10 10, 10 20) equals LineString(10 10, 10 15, 10 20)

- At its most trivial, two polygons may be comprised of the same points but have a different starting point.
- A more subtle issue is in GeometryCollections, this function seem to ignore anything in the interior. So if the external polygons are the same then it doesn't seem to matter if there are extra lines, points, polygons contained within each one.

# More info

For more info see SQL Server 2008 Books Online Geometry Methods Supported by Spatial Indexes

Please give feedback. Is this series of articles useful? Did it save you time? What was good, What could be better?, Notice any errors? What would you like me to cover? All thoughts, comments, suggestions welcome.