PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Nome da tabela como parâmetro de função do PostgreSQL


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. (Uma regclass parâmetro só é aplicável para existente tabelas.)

  • .. ele funciona com nomes de tabela qualificados pelo esquema, onde um simples quote_ident(_tbl) ou format(%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