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

PostgreSQL - Escrevendo sql dinâmico em procedimento armazenado que retorna um conjunto de resultados


Há espaço para melhorias:
CREATE OR REPLACE FUNCTION report_get_countries_new (starts_with text
                                                   , ends_with   text = NULL)
  RETURNS SETOF lookups.countries AS
$func$
DECLARE
   sql text := 'SELECT * FROM lookups.countries WHERE country_name >= $1';
BEGIN
   IF ends_with IS NOT NULL THEN
      sql := sql || ' AND country_name <= $2';
   END IF;

   RETURN QUERY EXECUTE sql
   USING starts_with, ends_with;
END
$func$ LANGUAGE plpgsql;
-- the rest is default settings

Pontos principais


  • O PostgreSQL 8.4 introduziu o USING cláusula para EXECUTE , que é útil por vários motivos. Recapitulando no manual:

    A string de comando pode usar valores de parâmetro, que são referenciados no comando como $1, $2 , etc. Esses símbolos referem-se a valores fornecidos no USING cláusula. Esse método geralmente é preferível a inserir valores de dados na string de comando como texto:ele evita a sobrecarga de tempo de execução de converter os valores em texto e vice-versa, e é muito menos propenso a ataques de injeção de SQL, pois não há necessidade de citação ou escape.

    IOW, é mais seguro e rápido do que construir uma string de consulta com representação de texto de parâmetros, mesmo quando higienizada com quote_literal() .
    Observe que $1, $2 na string de consulta referem-se aos valores fornecidos no USING cláusula, não aos parâmetros da função.

  • Enquanto você retorna SELECT * FROM lookups.countries , você pode simplificar o RETURN declaração como demonstrado:
    RETURNS SETOF lookups.countries
    

    No PostgreSQL existe um tipo composto definido automaticamente para cada tabela. Use-o. O efeito é que a função depende do tipo e você recebe uma mensagem de erro se tentar alterar a tabela. Solte e recrie a função nesse caso.

    Isso pode ou não ser desejável - geralmente é! Você quer estar ciente dos efeitos colaterais se alterar as tabelas. Do jeito que você tem, sua função quebraria silenciosamente e geraria uma exceção na próxima chamada.

  • Se você fornecer um padrão explícito para o segundo parâmetro na declaração como demonstrado, você pode (mas não precisa) simplificar a chamada caso não queira definir um limite superior com ends_with .
    SELECT * FROM report_get_countries_new('Zaire');
    

    ao invés de:
    SELECT * FROM report_get_countries_new('Zaire', NULL);
    

    Esteja ciente da sobrecarga de função neste contexto.

  • Não cite o nome do idioma 'plpgsql' mesmo que isso seja tolerado (por enquanto). É um identificador.

  • Você pode atribuir uma variável no momento da declaração. Salva uma etapa extra.

  • Os parâmetros são nomeados no cabeçalho. Solte as linhas sem sentido:
     starts_with ALIAS FOR $1;
     ends_with ALIAS FOR $2;