Su función podría verse así:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS SETOF transactions AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM transactions
WHERE ' || quote_ident(_col) || ' = $1
LIMIT $2'
USING _val, _limit;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
EN PostgreSQL 9.1 o posterior eso es más simple con format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
escapa de identificadores como quote_ident()
.
Puntos principales:
-
Estaba chocando con la limitación de SQL dinámico que no puede usar parámetros para identificadores. Tienes que construir la cadena de consulta con el nombre de la columna y luego ejecutarlo.
-
Sin embargo, puedes hacer eso con valores. Demuestro el uso del
USING
cláusula paraEXECUTE
. También tenga en cuenta el uso dequote_ident()
:previene la inyección SQL y ciertos errores de sintaxis. -
También simplifiqué en gran medida su función.
[RETURN QUERY EXECUTE][3]
hace que su código sea más corto y más rápido. No es necesario repetir si todo lo que hace es devolver la fila. -
Uso el nombre
IN
parámetros, para que no se confunda con la notación $ en la cadena de consulta.$1
y$2
dentro de la cadena de consulta, consulte los valores proporcionados enUSING
cláusula, no a los parámetros de entrada. -
Cambio a
SELECT *
ya que tiene que devolver la fila completa para que coincida con el tipo de devolución declarado de todos modos. -
Por último, pero no menos importante:asegúrese de considerar lo que dice el manual sobre las funciones declaradas
SECURITY DEFINER
.
TIPO DE DEVOLUCIÓN
Si no desea devolver la fila completa, una posibilidad conveniente es:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Entonces no tiene que proporcionar una lista de definición de columna con cada llamada y puede simplificar a:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);