You can use the distance-to operator (<->
) combined with the MIN
aggregate function to find the closest distance, thus reducing the problem to finding the other columns for the row with some minimal quantity. The strictly left of/right of/above/below operators (<<
, >>
, |>>
, <<|
) can be used to limit the points to one side of the box. Since two different points might have the same distance, we'll limit the result to 1 row. Assuming screen orientation, where coordinates increase down and to the right (rather than map orientation, which increases North and East), we get:
-- Above, or North
SELECT * FROM ch WHERE loc <<| screen AND (loc <-> screen) = (
SELECT MIN(loc <-> screen) AS mindist FROM ch
WHERE loc <<| screen
) LIMIT 1
-- Right, or East
SELECT * FROM ch WHERE loc >> screen AND (loc <-> screen) = (
SELECT MIN(loc <-> screen) AS mindist FROM ch
WHERE loc >> screen
) LIMIT 1
-- Below, or South
SELECT * FROM ch WHERE loc |>> screen AND (loc <-> screen) = (
SELECT MIN(loc <-> screen) AS mindist FROM ch
WHERE loc |>> screen
) LIMIT 1
-- Left, or West
SELECT * FROM ch WHERE loc << screen AND (loc <-> screen) = (
SELECT MIN(loc <-> screen) AS mindist FROM ch
WHERE loc << screen
) LIMIT 1
Note that the closest point in a horizontal direction might also be the closest point in a vertical direction; that is, the union of the above four statements might be less than four rows.
We can get the four closest points with:
SELECT *, (loc <-> screen) AS distance FROM ch
WHERE NOT loc <@ screen
ORDER BY distance
LIMIT 4
However, note that some of the closest points might be in the same direction as each other.
We can get the closest point overall with
SELECT *, (loc <-> screen) AS distance FROM ch
WHERE distance = (
SELECT MIN(loc <-> screen) AS mindist FROM ch
)
LIMIT 1
or
SELECT *, (loc <-> screen) AS distance FROM ch
WHERE NOT loc <@ screen
ORDER BY distance
LIMIT 1
When calculating the minimum (or maximum) of a column, the first would be preferable, since the DBMS could use an index on the column (if any) and not need to scan the table. Since the distance is a calculated value, a table scan is always needed and the queries will have similar performance. A query analysis might turn up some other reason to prefer a statement, so you should do so before picking an approach.