Finding the closest Geometry in PostGIS
Your question can be also answered by a single (albeit complex) query like the following which returns the whole record and the distance to the reference geometry. Please note that if more than one record matches the min distance they are all returned.
SELECT
i.*,
md.min_distance
FROM
address AS i,
(SELECT
ga.address_geom,
min( ST_Distance(
ga.address_geom,
gb.address_geom)
) AS min_distance
FROM
address AS ga,
address AS gb
WHERE
ga.id <> gb.id
AND
ga.id = 3
GROUP BY
ga.address_geom
) AS md
WHERE
ST_Distance( i.address_geom, md.address_geom) = md.min_distance;
I have tested this query on table of addresses and it works. In the query above I am looking for nearest point to that with id=3.
George MacKerron has written a simple Nearest Neighbor function which I've found quite useful. This function returns the ID of the nearest neighbor to a given feature:
create or replace function
nn(nearTo geometry
, initialDistance real
, distanceMultiplier real
, maxPower integer
, nearThings text
, nearThingsIdField text
, nearThingsGeometryField text)
returns integer as $$
declare
sql text;
result integer;
begin
sql := ' select ' || quote_ident(nearThingsIdField)
|| ' from ' || quote_ident(nearThings)
|| ' where st_dwithin($1, '
|| quote_ident(nearThingsGeometryField) || ', $2 * ($3 ^ $4))'
|| ' order by st_distance($1, ' || quote_ident(nearThingsGeometryField) || ')'
|| ' limit 1';
for i in 0..maxPower loop
execute sql into result using nearTo -- $1
, initialDistance -- $2
, distanceMultiplier -- $3
, i; -- $4
if result is not null then return result; end if;
end loop;
return null;
end
$$ language 'plpgsql' stable;
Usage example:
SELECT id, nn(pt_geom,0.00001,2,100,'nw_node','node_id','node_geom') FROM my_point_table;
... selects the nearest node in nw_node table for every entry in my_point_table.
There is also a more generic function on the Boston GIS site.