Isso pode ser ainda mais simplificado e melhorado:
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$;
Chamada com nome qualificado pelo esquema (veja abaixo):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Ou:
SELECT some_f('"my very uncommon table name"');
Pontos principais
Use um
OUT parâmetro para simplificar a função. Você pode selecionar diretamente o resultado do SQL dinâmico e pronto. Não há necessidade de variáveis e códigos adicionais. EXISTS faz exatamente o que você quer. Você obtém true se a linha existir ou false por outro lado. Existem várias maneiras de fazer isso, EXISTS normalmente é mais eficiente. Você parece querer um inteiro de volta, então eu converto o
boolean resultado de EXISTS para integer , que produz exatamente o que você tinha. Eu retornaria boolean em vez de. Eu uso o tipo de identificador de objeto
regclass como tipo de entrada para _tbl . Isso faz tudo quote_ident(_tbl) ou format('%I', _tbl) faria, mas melhor, porque:-
.. impede a injeção de SQL tão bem.
-
.. ele falha imediatamente e com mais graça se o nome da tabela for inválido / não existir / for invisível para o usuário atual. (Umaregclassparâmetro só é aplicável para existente tabelas.)
-
.. ele funciona com nomes de tabela qualificados pelo esquema, onde um simplesquote_ident(_tbl)ouformat(%I)falharia porque eles não podem resolver a ambiguidade. Você teria que passar e escapar nomes de esquema e tabela separadamente.
Funciona apenas para existentes mesas, obviamente.
Eu ainda uso
format() , porque simplifica a sintaxe (e para demonstrar como é usada), mas com %s em vez de %I . Normalmente, as consultas são mais complexas, então format() ajuda mais. Para o exemplo simples, poderíamos apenas concatenar:EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Não há necessidade de qualificar a tabela
id coluna enquanto houver apenas uma única tabela no FROM Lista. Nenhuma ambiguidade é possível neste exemplo. Comandos SQL (dinâmicos) dentro de EXECUTE ter um escopo separado , variáveis ou parâmetros de função não são visíveis lá - ao contrário de comandos SQL simples no corpo da função. É por isso que você sempre escape da entrada do usuário para SQL dinâmico corretamente:
db<>mexa aqui demonstrando injeção de SQL
antigo sqlfiddle