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

Para converter de arrays Python para PostgreSQL rapidamente?

Configuração


Você deseja criar gatilhos (repetidamente?) usando a mesma função de gatilho, conforme descrito em minha resposta relacionada em dba.SE . Você precisa passar valores para a função de gatilho para criar múltiplos linhas com múltiplas valores de coluna, daí a matriz bidimensional. (Mas podemos trabalhar com qualquer string claramente definida!)

A única maneira de passar valores para uma função de gatilho PL/pgSQL (além dos valores de coluna da linha de gatilho) é text parâmetros, que são acessíveis dentro da função como 0- matriz de texto baseada na variável de matriz especial TG_ARGV[] . Você pode passar um número variável de parâmetros, mas discutimos uma única string literal representando seu array bidimensional anteriormente.

A entrada vem de uma matriz Python bidimensional com inteiro assinado números, que se encaixam no tipo Postgres integer . Use o tipo Postgres bigint para cobrir números inteiros não assinados, como comentou .

A representação de texto em Python é assim:
[[1,2],[3,4]]

Sintaxe para um literal de matriz Postgres:
{{1,2},{3,4}}

E você quer automatizar o processo.

Automação total


Você pode concatenar a string para o CREATE TRIGGER instrução em seu cliente ou você pode persistir a lógica em uma função do lado do servidor e apenas passar parâmetros.

Demonstrando uma função de exemplo que recebe um nome de tabela e a string que é passada para a função de gatilho. A função de gatilho insaft_function() está definido em sua pergunta anterior sobre dba.SE .
CREATE OR REPLACE FUNCTION f_create_my_trigger(_tbl regclass, _arg0 text)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format($$
      DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;
      CREATE TRIGGER insaft_%1$s_ids
      AFTER INSERT ON %1$s
      FOR EACH ROW EXECUTE PROCEDURE insaft_function(%2$L)$$
                , _tbl
                , translate(_arg0, '[]', '{}')
      );
END 
$func$;

Ligar:
SELECT f_create_my_trigger('measurements', '[[1,2],[3,4]]');

Ou:
SELECT f_create_my_trigger('some_other_table', '{{5,6},{7,8}}');

db<>fiddle aqui
Antigo sqlfiddle

Agora você pode passar [[1,2],[3,4]] (com colchetes) ou {{1,2},{3,4}} (com chaves). Ambos funcionam da mesma forma. translate(_arg0, '[]', '{}' transforma a primeira na segunda forma.

Esta função descarta um gatilho de mesmo nome, se existir, antes de criar o novo. Você pode querer descartar ou manter esta linha:
DROP TRIGGER IF EXISTS insaft_%1$s_ids ON %1$s;

Isso é executado com os privilégios da função de banco de dados de chamada. Você pode fazê-lo rodar com privilégios de superusuário (ou qualquer outro) se necessário. Ver:

Há muitas maneiras de conseguir isso. Depende dos requisitos exatos.

Explicando format()


format() e o tipo de dados regclass ajudam a concatenar com segurança o comando DDL e impossibilitam a injeção de SQL. Ver:

O primeiro argumento é a "string de formato", seguido pelos argumentos a serem incorporados na string. Eu uso cotações de dólares , que não é estritamente necessário para o exemplo, mas geralmente é uma boa ideia para concatenar longas strings contendo aspas simples:$$DROP TRIGGER ... $$

formato() é modelado ao longo da função C sprintf . %1$s é um especificador de formato do formato ( ) função. Isso significa que o primeiro (1$ ) após a string de formato ser inserida como string sem aspas (%s ), portanto:%1$s . O primeiro argumento para formatar é _tbl no exemplo - a regclass parâmetro é renderizado como identificador legal automaticamente, com aspas duplas se necessário, então format() não precisa fazer mais. Portanto, apenas %s , não %I (identificador). Leia a resposta vinculada acima para obter detalhes.
O outro especificador de formato em uso é %2$L :Segundo argumento como literal de string entre aspas .

Se você é novo em format() , brinque com estes exemplos simples para entender:
SELECT format('input -->|%s|<-- here', '[1,2]')
     , format('input -->|%s|<-- here', translate('[1,2]', '[]', '{}'))
     , format('input -->|%L|<-- here', translate('[1,2]', '[]', '{}'))
     , format('input -->|%I|<-- here', translate('[1,2]', '[]', '{}'));

E leia o manual .