Reputation: 17388
I am using this simple correlated sub-query to find the closest place to a place (example simplified of course):
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp
CREATE TABLE #Temp
(
FromPlaceId INT NOT NULL,
FromPlaceName [NVARCHAR](255) NOT NULL,
ToPlaceId INT NOT NULL,
ToPlaceName [NVARCHAR](255) NOT NULL,
Distance FLOAT NOT NULL
)
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 1, N'Place1' , 2 , N'Place2' , 1.0 )
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 1, N'Place1' , 3 , N'Place3' , 2.0 )
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 2, N'Place2' , 1 , N'Place1' , 1.0 )
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 2, N'Place2' , 3 , N'Place3' , 13.0 )
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 3, N'Place3' , 1 , N'Place1' , 2.0 )
INSERT INTO #Temp( FromPlaceId, FromPlaceName, ToPlaceId, ToPlaceName, Distance) VALUES ( 3, N'Place3' , 2 , N'Place2' , 13.0 )
SELECT * FROM #Temp
SELECT
a.FromPlaceId,
a.FromPlaceName,
a.ToPlaceId,
a.ToPlaceName,
a.Distance
FROM #temp AS a WHERE a.Distance =
(
SELECT TOP 1 b.Distance FROM #Temp AS b WHERE a.FromPlaceId = b.FromPlaceId
ORDER BY b.Distance ASC
)
I am just wondering how to get the 2 or 3 closest places. Obviously, a correlated sub query does not work in this scenario.
Upvotes: 1
Views: 41
Reputation: 44881
If I understand your requirement right I think you should be able use the rank()
window function like this:
SELECT * FROM (
SELECT
FromPlaceId,
FromPlaceName,
ToPlaceId,
ToPlaceName,
Distance,
rank = RANK() OVER (PARTITION BY FromPlaceId ORDER BY Distance)
FROM #temp
) a
WHERE rank <= 2;
This would return all the ToPlaceId for each FromPlaceId that have a distance that is in the top two closest, so if several ToPlaceId have the same distance all would be returned.
Changing your current query to use in
and top 2
in the correlated query should also work, although I think the window function might perform better.
FROM #temp AS a WHERE a.Distance IN
(
SELECT TOP 2 b.Distance
Upvotes: 2