Esto se puede simplificar y mejorar aún más:
CREATE OR REPLACE FUNCTION some_f(_tbl regclass, OUT result integer)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (EXISTS (SELECT FROM %s WHERE id = 1))::int', _tbl)
INTO result;
END
$func$;
Llamada con nombre calificado de esquema (ver a continuación):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
O:
SELECT some_f('"my very uncommon table name"');
Puntos principales
Usa un OUT
parámetro para simplificar la función. Puede seleccionar directamente el resultado del SQL dinámico y listo. No se necesitan variables ni código adicionales.
EXISTS
hace exactamente lo que quieres. Obtienes true
si la fila existe o false
de lo contrario. Hay varias formas de hacer esto, EXISTS
suele ser más eficiente.
Parece que quieres un entero atrás, así que lanzo el boolean
resultado de EXISTS
a integer
, que produce exactamente lo que tenía. Devolvería booleano en su lugar.
Uso el tipo de identificador de objeto regclass
como tipo de entrada para _tbl
. Eso hace todo quote_ident(_tbl)
o format('%I', _tbl)
haría, pero mejor, porque:
-
.. previene la inyección SQL igual de bien.
-
.. falla inmediatamente y con más gracia si el nombre de la tabla no es válido/no existe/es invisible para el usuario actual. (Una
regclass
el parámetro solo es aplicable para existente tablas.) -
.. funciona con nombres de tablas calificados por esquemas, donde un simple
quote_ident(_tbl)
oformat(%I)
fallarían porque no pueden resolver la ambigüedad. Tendría que pasar y escapar los nombres de esquema y tabla por separado.
Solo funciona para existentes mesas, obviamente.
Todavía uso format()
, porque simplifica la sintaxis (y para demostrar cómo se usa), pero con %s
en lugar de %I
. Por lo general, las consultas son más complejas, por lo que format()
ayuda más Para el ejemplo simple, también podríamos simplemente concatenar:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
No es necesario calificar en tabla el id
columna mientras que solo hay una tabla en el FROM
lista. No hay ambigüedad posible en este ejemplo. Comandos SQL (dinámicos) dentro de EXECUTE
tener un alcance separado , las variables de función o los parámetros no están visibles allí, a diferencia de los comandos SQL simples en el cuerpo de la función.
Esta es la razón por la que siempre escape de la entrada del usuario para SQL dinámico correctamente:
db<>violín aquí demostración de inyección SQL
Sqlfiddle antiguo