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

Função INSERT em massa do Postgres usando argumentos JSON

Para milhares de registros


1. Crie uma tabela temporária de linhas de entrada, composta por seus valores $1 , $2 , $3 . A maneira mais rápida de fazer upload é COPY - ou o \copy meta-comando do psql se os dados não estiverem na mesma máquina. Vamos supor esta tabela:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);

Eu adicionei uma restrição PK, que é totalmente opcional, mas garante que estamos lidando com valores int não nulos exclusivos. Se você puder atestar os dados de entrada, não precisará da restrição.

2. Encadeie seus comandos com CTEs de modificação de dados. Conforme determinamos em sua pergunta anterior , não há condições de corrida para cuidar nesta operação específica.
WITH ins1 AS (
   INSERT INTO table1 AS t1 (id, val1, val2)
   SELECT id, val1, val2 FROM tmp ON CONFLICT DO NOTHING
   RETURNING t1.id, t1.val1, t1.val2  -- only actually inserted rows returned
   )
, ins2 AS (
   INSERT INTO table2 (table1_id, val1)
   SELECT id, val1 FROM ins1
   )
UPDATE table3 t3
SET    val2 = i.val2
     , time = now()
FROM   ins1 i
WHERE  t3.table1_id = i.id;

As etapas 1 e 2 devem ser executadas na mesma sessão (não necessariamente a mesma transação), pois o escopo das tabelas temporárias está vinculado à mesma sessão.

Observe que o UPDATE depende apenas do 1º INSERT , sucesso do 2º INSERT é garantido, uma vez que não há ON CONFLICT DO NOTHING e toda a operação seria revertida se houver algum conflito no 2º INSERT .

Relacionado:

Por apenas alguns registros


Existem várias opções como. Sua ideia de passar um array JSON para uma função é uma delas. Se os objetos corresponderem à tabela de destino, você poderá usar json_populate_recordset() em um único INSERT consulta. Ou apenas use o INSERT (como instrução preparada) sem wrapper de função.
INSERT INTO target_tbl  -- it's ok to omit target columns here
SELECT *
FROM   json_populate_recordset(null::target_tbl,  -- use same table type
          json '[{ "id": "1", "val1": "1-val1", "val2": "1-val2" },
                 { "id": "2", "val1": "2-val1", "val2": "2-val2" },
                 { "id": "3", "val1": "3-val1", "val2": "3-val2" },
                 { "id": "4", "val1": "4-val1", "val2": "4-val2" }]');

Para apenas um punhado de colunas, você também pode passar uma matriz para cada coluna e percorrê-las em paralelo. Você pode fazer isso com um loop simples no índice do array. Desde o Postgres 9.4 também existe o conveniente unnest() com vários parâmetros para fazer tudo em uma única consulta:

A melhor solução depende do formato de dados que você tem .