sql >> Base de Datos >  >> RDS >> PostgreSQL

Nombre de tabla como parámetro de función de PostgreSQL

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) o format(%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