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