It is impossible to get around the fact that you have to compare each entry in with each entry in B, which obviously will not scale well if both A and B contain many entries.
This will return the correct results:
SELECT aid, bid, distanceAB FROM ( SELECT aid, bid, distanceAB, dense_rank() over (partition by aid order by distanceAB) as n FROM ( SELECT a.id as aid, B.id as bid, acos(sin(radians(A.lat)) * sin(radians(B.lat)) + cos(radians(A.lat)) * cos(radians(B.lat)) * cos(radians(A.lon - B.lon))) * 6372.8 as distanceAB FROM A cross join B ) C ) D WHERE n = 1
This will be returned within a reasonable time if your sets are not too large. With 3 places in and 130,000 or so in B, it takes about one second on my car. 1000 entries in each takes about 40 seconds. As I said, it does not scale well.
It should be noted that Sparky's answer may lead to incorrect results in certain circumstances. Suppose your location A is at + 40, + 100. + 40, + 111 will not be returned, although it is closer than + 49, + 109.
source share