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

Como atualizar linhas selecionadas com valores de um arquivo CSV no Postgres?


COPY o arquivo para uma tabela de preparo temporária e atualize a tabela real de lá. Como:
CREATE TEMP TABLE tmp_x (id int, apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

Se a tabela importada corresponder exatamente à tabela a ser atualizada, isso pode ser conveniente:
CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

Cria uma tabela temporária vazia que corresponde à estrutura da tabela existente, sem restrições.

Privilégios


Até Postgres 10, SQL COPY requer privilégios de superusuário para isso.
No Postgres 11 ou posterior, também existem algumas funções predefinidas (anteriormente "funções padrão") para permitir isso. O manual:

COPY nomear um arquivo ou comando só é permitido a superusuários do banco de dados ou usuários que recebem uma das funções pg_read_server_files ,pg_write_server_files , ou pg_execute_server_program [...]

O psql meta-comando \copy funciona para qualquer função de banco de dados. O manual:

Executa uma cópia de frontend (cliente). Esta é uma operação que executa um SQL COPY mas em vez do servidor ler ou gravar o arquivo especificado, o psql lê ou grava o arquivo e roteia os dados entre o servidor e o sistema de arquivos local. Isso significa que a acessibilidade e os privilégios do arquivo são aqueles do usuário local, não do servidor, e nenhum privilégio de superusuário SQL é necessário.

O escopo das tabelas temporárias é limitado a uma única sessão de um único papel, então o acima deve ser executado na mesma sessão do psql:
CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

Se você estiver criando um script em um comando bash, certifique-se de envolver tudo em um único chamada psql. Como:
echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

Normalmente, você precisa do meta-comando \\ para alternar entre comandos meta do psql e comandos SQL no psql, mas \copy é uma exceção a esta regra. O manual novamente:

regras especiais de análise se aplicam ao \copy meta-comando. Ao contrário da maioria dos outros metacomandos, todo o restante da linha é sempre considerado como sendo os argumentos de \copy , e nem a interpolação de variável nem a expansão de backquote são executadas nos argumentos.

Mesas grandes


Se a tabela de importação for grande, pode valer a pena aumentar temp_buffers temporariamente para a sessão (primeira coisa na sessão):
SET temp_buffers = '500MB';  -- example value

Adicione um índice à tabela temporária:
CREATE INDEX tmp_x_id_idx ON tmp_x(id);

E execute ANALYZE manualmente, pois as tabelas temporárias não são cobertas pelo autovacuum / auto-analyze.
ANALYZE tmp_x;

Respostas relacionadas:
  • Melhor maneira de excluir milhões de linhas por ID
  • Como posso inserir dados comuns em uma tabela temporária de esquemas diferentes?
  • Como excluir entradas duplicadas?