1

I need to show the three closest hospitals to every house. I have a table of properties and a table of hospitals. Both are in MSSQL2012, have a geography column that is indexed and are in the same 4326 SRID.

I cant find any examples on how to perform ST_Distance across different tables, returning the top 3.

As per Evans suggestion i have tried the following but the query is not valid

SELECT *
FROM (
 SELECT * , row_number OVER (
 PARTITION BY [dbo].[houses].[geogtab]
 ORDER BY [dbo].[houses].[geogtab].STDistance([dbo].[hospitals].[geogtab]) ASC
 ) AS i
 FROM [dbo].[houses]
 JOIN [dbo].[hospitals]
 ON [dbo].[houses].[geogtab].STBuffer(100000).STIntersects([dbo].[hospitals].[geogtab])
 ORDER BY [dbo].[houses].[geogtab].STDistance([dbo].[hospitals].[geogtab] ) ASC
) AS t
WHERE t.i <= 3;

I am unsure if this is formatting related and am unsure from reading this if the distance will be an output in the result table.

Matthias Kuhn
28.4k3 gold badges92 silver badges133 bronze badges
asked Jan 2, 2018 at 15:31
3
  • Confused; Is this a PostGIS or a SQL Server question? Commented Jan 3, 2018 at 11:27
  • Hey Dennis, SQL Server. Commented Jan 4, 2018 at 8:50
  • Can you remove the postgis tag from the post? This will help filter the question for people who may be able to help. Commented Jan 4, 2018 at 12:38

1 Answer 1

3

4326 SRID

Microsoft SQL doesn't use SRID, so 4326 or 9999 isn't a problem. Like MySQL they just error on SRID mismtach. They do have a geographic object. They also don't follow any spec whatsoever with their spatial interface. It's really just a link to their Microsoft Java/.NET stuff and a veneer that sometimes look standardized.

Create your points with something like this,

-- No st_point in this bizzaro world
geography::Point(47.65100, -122.34900, 4326)

Find point-in-polygon boolean searches with STIntersects(). For the SqlGeography class this is essentially the PostGIS equivalent of ST_DWithin. At least it uses an index if you have one.

CREATE TABLE #tmp (
 geog geography,
);
INSERT INTO #tmp(geog) VALUES
 (geography::Point(1,1,4326)),
 (geography::Point(1.5,1.5,4326)),
 (geography::Point(2,2,4326));
SELECT geography::Point(1,1,4326).STBuffer(100000).STIntersects(geog)
FROM #tmp;

In the above, we're finding all points within 100000 meters of the CAST( ST_Point(1,1) AS geography)

Joining is just as simple.

FROM t1
JOIN t2
 ON t1.geog.STBuffer(100000).STIntersects(t2.geog)

Finding the top three JOIN and then ORDER BY distance.

SELECT *
FROM (
 SELECT * , row_number OVER (
 PARTITION BY t1.geog
 ORDER BY t1.geog.STDistance( t2.geog ) ASC
 ) AS i
 FROM t1
 JOIN t2
 ON t1.geog.STBuffer(100000).STIntersects(t2.geog)
 ORDER BY t1.geog.STDistance( t2.geog ) ASC
) AS t
WHERE t.i <= 3;

Importantly I don't think the KNN stuff (or anything else for that matter) is as sophisticated as PostGIS. For instance on Spatial KNN say,

The first expression in the ORDER BY clause must use the STDistance() method.

In this construction we do that, but I'm not sure that the planner will plan KNN.

You can always ask another question specifically about the indexing problem you encounter on this site or on Database Administrators (tag with spatial)

answered Jan 2, 2018 at 19:05
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.