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

plpgsql - usando o nome da tabela dinâmica na declaração de declaração


É importante entender a natureza principal desses cinco diferentes tipos de dados/símbolos :

1. 'my_tbl'


Um literal de string de unknown tipo . Quando usado em SQL (embutido no código plpgsql ou não), ele é forçado a um tipo derivado do contexto . Se o tipo não puder ser determinado, uma conversão explícita pode ser necessária. Como:'my_tbl'::text .

2. 'my_tbl'::text


O mesmo literal de string convertido para digite text . Ele pode conter o nome de uma tabela, mas na verdade é apenas texto.

3. 'my_tbl'::regclass


Um identificador de objeto (OID) para uma classe registrada . Ele é exibido e pode ser inserido como uma string representando um nome de objeto válido ('my_tbl' ). A saída é automaticamente qualificada pelo esquema ('my_schema.my_tbl' ) e/ou aspas duplas ('"mY_TbL"' ) se for ambíguo ou ilegal de outra forma. Pode ser uma tabela normal , sequência , ver , visualização materializada , tipo composto etc. Detalhes nesta resposta relacionada:

4. my_tbl_var my_tbl (abreviação de my_tbl_var my_tbl%ROWTYPE )


No DECLARE seção de um bloco de código plpgsql que é uma declaração de variável com um conhecido tipo de linha (também conhecido como tipo composto). O tipo deve ser registrado na tabela do sistema pg_class (o mesmo que com uma regclass variável). Não é o OID do objeto referenciado, mas seu tipo de linha real. my_tbl_var e my_tbl são ambos identificadores aqui e não pode ser parametrizado. Você também pode converter qualquer linha ou registro diretamente:(123, 'foo')::my_tbl

5. my_tbl_var record


No DECLARE seção de um bloco de código plpgsql que é a declaração de um anônimo registro . Basicamente, um espaço reservado para um tipo de linha ainda desconhecido / com estrutura ainda indefinida. Pode ser usado na maioria dos locais em que um tipo de linha pode ser usado. Mas você não pode acessar campos dele antes que a variável de registro seja atribuída.

Você estava confundindo 1. , 3. e 4. e resolveu usando 5. em vez disso.
Mas há mais coisas erradas aqui:

  • Você está selecionando uma tabela inteira, mas uma variável de linha (registro) pode conter apenas uma linha por vez. Portanto, apenas o primeiro é atribuído e retornado. Enquanto não houver ORDER BY cláusula, o resultado é arbitrário e pode mudar a qualquer momento. Armadilha do mal.

  • Como agora você está usando um record type, você precisa ter certeza de que ele foi atribuído antes de executar testes em seus campos, ou você obterá exceções para tabelas vazias. No seu caso, a verificação record_var IS NULL quase faz o mesmo trabalho. Mas há um caso de canto para linhas com NULL em todos os campos:então record_var IS NULL avalia como verdadeiro. Ainda mais complicado para o teste IS NOT NULL . Detalhes aqui:

    Adicionei uma demonstração ao fiddle SQL abaixo de.

  • A função retorna um único escalar (boolean ) valor. Usar:
    RETURN false;
    

    Ao invés de:
    RETURN QUERY SELECT false;

Função

CREATE FUNCTION check_valid(_tbl regclass)
  RETURNS bool AS
$func$
DECLARE
   r record;
   _row_ct int;
BEGIN
   EXECUTE '
   SELECT is_valid, hit_count, hit_limit
   FROM  ' || _tbl || '
   ORDER  <whatever>
   LIMIT  1'            -- replace <whatever> with your sort criteria
   INTO r;              -- only needed columns

   GET DIAGNOSTICS _row_ct = ROW_COUNT;

   IF _row_ct = 0 THEN  -- necessary, because r may not be assigned
      RETURN false;
   ELSIF NOT r.is_valid OR r.hit_count > r.hit_limit THEN
      RETURN false;
   END IF;

   RETURN true;
END
$func$  LANGUAGE plpgsql;

SQL Fiddle (com duas variantes da função e uma demonstração para a linha IS NULL).

Pontos principais


  • Use GET DIAGNOSTICS para descobrir se alguma linha foi encontrada em uma instrução dinâmica com EXECUTE .

  • O IF expressão pode ser simplificada.

  • O parâmetro é do tipo regclass , não apenas um nome de tabela. Eu não usaria o nome enganoso "tablename" para esse parâmetro. Isso só aumenta sua confusão inicial. Chamando de _tbl em vez de.

Se você também quiser retornar um conjunto de tipo de linha variável: