I have to convert from lat and long to geom
to use PostGIS. My problem, I have various tables from different locations and I want to pass the table as a parameter to the function. I'm trying this:
CREATE or REPLACE FUNCTION convert_from_lon_lat(float,float,character varying)
RETURNS integer AS $$
select id from $3 as vertices
order by vertices.geom <-> ST_SetSrid(ST_MakePoint($1,$2),4326) LIMIT 1;
$$ LANGUAGE SQL;
but I get a syntax error.
EDIT1:
So I changed the previous code to this:
CREATE or REPLACE FUNCTION convert_from_lon_lat(long float, lat float, _table character varying) RETURNS integer AS $$
BEGIN
EXECUTE('select id from _table as vertices order by vertices.geom <-> ST_SetSrid(ST_MakePoint(long,lat),4326) LIMIT 1;');
END;
$$ LANGUAGE plpgsql;
it creates without any problem, but when I call it `convert_from_lon_lat(long1, long2, my_table)
I get and error:
ERROR: relation "_table" does not exist
It's not passing the table name as an argument
EDIT 2:
CREATE or REPLACE FUNCTION convert_from_lon_lat(long float, lat float, tbl character varying) RETURNS integer AS $func$
BEGIN
EXECUTE format('select id from %s order by %s.the_geom <-> ST_SetSrid(ST_MakePoint('|| long || ','|| lat ||'),4326) LIMIT 1;', tbl, tbl);
END;
$func$ LANGUAGE plpgsql;
Now when I call the function, I get an `ERROR: control reached end of function without RETURN``
I tried RETURN QUERY EXECUTE format('...
but I get a ERROR: cannot use RETURN QUERY in a non-SETOF function
AS @dezso mentioned, you'll need dynamic SQL in this case.
Dynamic SQL with EXECUTE
So, you're on the right track; forming a dynamic SQL statement using PL/pgSQL, but you just need the finishing touches:
CREATE or REPLACE FUNCTION convert_from_lon_lat(long float, lat float, _table text)
RETURNS integer AS $$
BEGIN
RETURN QUERY EXECUTE format('SELECT id FROM %I AS vertices
ORDER BY vertices.geom <->ST_SetSrid(ST_MakePoint(long,lat),4326) LIMIT 1;',_table);
END
$$ LANGUAGE plpgsql;
I believe this should solve your issues.
Note: We've discovered an error with the above solution and using SETOF
, I've attempted to correct the issues below.
EDIT:
A few edits here, hopefully one solution will fix your issue. Also, please excuse any syntax errors in my previous & current solutions; I don't have time to test them right now. :(
1) You could just try returning a SETOF
integers, knowing that of course you'll only return the one. Your return type in this case will then be a single, one-column row containing an integer.
CREATE or REPLACE FUNCTION convert_from_lon_lat(long float, lat float, _table text)
RETURNS SETOF integer AS $$
BEGIN
RETURN QUERY EXECUTE format('SELECT id FROM %I AS vertices
ORDER BY vertices.geom <->ST_SetSrid(ST_MakePoint(long,lat),4326) LIMIT 1;',_table);
END
$$ LANGUAGE plpgsql;
and then call as:
SELECT * FROM convert_from_lon_lat(...);
2) To specifically return an integer, I think you can try this:
CREATE or REPLACE FUNCTION convert_from_lon_lat(long float, lat float, _table text)
RETURNS integer AS $$
DECLARE
return_id integer;
BEGIN
EXECUTE format('SELECT id FROM %I AS vertices
ORDER BY vertices.geom <->ST_SetSrid(ST_MakePoint(long,lat),4326) LIMIT 1;',_table)
INTO return_id;
RETURN return_id;
END
$$ LANGUAGE plpgsql;