Basically, if you try to do this yourself, you end up with a Cartesian product:
select c.*, ws.*
from cities c cross apply
(select ws.*
from (select ws.*,
<complicated expression to calculate distance> as distance
from weather_station ws
) ws
where distance < 100
) ws;
In order to get the list of weather stations, all cities and weather stations have to be compared. The distance calculation is often rather expensive, so you can cut down on this by "prefiltering". For instance, in most inhabited places, 100 km is within 1 degree latitude and 2 degrees longitude:
select c.*, ws.*
from cities c cross apply
(select ws.*
from (select ws.*,
<complicated expression to calculate distance> as distance
from weather_station ws
where ws.latitutde between c.latitude - 1 and c.latitude + 1 and
ws.longitude between c.longitude - 2 and c.longitude + 2
) ws
where distance < 100
) ws;
Although that helps, this is still essentially a filtered Cartesian product.
So, what should you really do? If you care about coordinates as spatial data, you should look into SQL Server's spatial extensions (the documentation is here, particularly the geography
type because that is most relevant to your needs).