O comando de cópia do cliente Postgres (\ copy) não ' tem acesso a uma tabela temporária?

Estou gerando uma lista de comandos SQL para exportar alguns dados que acabo por executar usando psql -f. Todas as consultas obtêm o mesmo subconjunto de dados, então pensei em fatorar as qualificações e colocar uma lista de IDs de usuário elegíveis em tabelas temporárias, como

create temporary table tmp_export_users as (select id from users where ...) 

e consultar isso em meu \ comandos de cópia como

\copy (select ... from table where user_id in (select id from tmp_export_users)) TO "filename.csv" WITH CSV HEADER 

Esses estão todos no mesmo arquivo, um por linha, e executando-os -f obtenho o erro de que os comandos de cópia podem ” Não vejo a tabela temporária, portanto, estou supondo que o comando de cópia do cliente não deve realmente usar a mesma sessão do postgres do psql.

Isso está correto? Existe uma maneira de mudar esse comportamento?

Resposta

\copy pode usar uma tabela temporária.

Primeiro testei e confirmei isso com a versão 9.0 na linha de comando.
Então criei um arquivo com o comando SQL e o meta-comando psql \copy usando várias tabelas temporárias. Isso também funcionou para mim.

CREATE TEMP TABLE tmp as SELECT * FROM tbl; \copy (SELECT * FROM tmp JOIN tbl USING (id)) TO "/var/lib/postgres/test1.csv"; 

Ligue:

psql -p5432 mydb -f test.sql 

Observe o encerramento ponto-e-vírgula, que é opcional no final de um arquivo (terminado implicitamente), mas necessário após qualquer outra instrução SQL e também após a última se executada no psql interativamente.

Normalmente , os meta-comandos psql não podem ser misturados com SQL na mesma linha em um arquivo executado por psql -f. Cito o manual do psql :

A análise de argumentos para no final de a linha, ou quando outra barra invertida não citada for encontrada. Uma barra invertida sem aspas é considerada o início de um novo meta-comando. A sequência especial \\ (duas barras invertidas) marca o fim dos argumentos e continua a analisar os comandos SQL, se houver. Dessa forma, os comandos SQL e psql podem ser misturados livremente em uma linha. Mas, em qualquer caso, os argumentos de um meta-comando não podem continuar além do final da linha.

Regras diferentes se aplicam após \copy, no entanto. Essencialmente, o psql volta ao modo SQL automaticamente após \copy Veja:

Mas você escreveu que tinha todos os comandos em linhas separadas. Portanto, essa não pode ser a explicação para o seu caso.


Deixando isso de lado, você já pensou em usar COPY (o comando SQL ) em vez de \copy ( o meta-comando psql )?

Obviamente, o arquivo de destino teria que ser local para o servidor não para o cliente neste caso. E diferentes privilégios de arquivo se aplicam. O manual :

Arquivos nomeados em COPY é lido ou escrito diretamente pelo servidor, não pelo aplicativo cliente. Portanto, eles devem residir ou estar acessíveis à máquina servidora de banco de dados, não ao cliente. Eles devem ser acessíveis e legíveis ou graváveis pelo usuário PostgreSQL (o ID do usuário com o qual o servidor é executado), não pelo cliente.

Comentários

  • a cópia é executada como o usuário postgres, \ copy envolve a cópia para gravar no std out e é redirecionado para o arquivo para o qual você a envia. Você também pode chamar o psql, usar \ o para enviar a saída para um arquivo e, em seguida, executar uma cópia para stdout para obter um efeito semelhante.
  • Para ter certeza de que executei o teste em minha resposta com um superusuário (postgres ) e um usuário fictício. Ambos trabalham para mim. Mesmos resultados na v8.4.
  • Sim, se o usuário postgres unix pode ou não acessar coisas como / tmp depende de coisas como se o SELinux está instalado ou não e se ele o deixa fora da caixa. O \ copy ou copy to stdout são definitivamente as duas maneiras mais confiáveis de usar o copy.
  • Obrigado a todos pelas respostas. Parece que esqueci de terminar a linha que criou uma tabela temporária com um ponto-e-vírgula, por isso ela não ' foi criada. Trabalhando como esperado agora

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *