Guardar salida PL / pgSQL de PostgreSQL en un archivo CSV

Respuestas:

1368

¿Desea el archivo resultante en el servidor o en el cliente?

Lado del servidor

Si desea algo fácil de reutilizar o automatizar, puede usar el comando COPY integrado de Postgresql . p.ej

Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER;

Este enfoque se ejecuta completamente en el servidor remoto : no puede escribir en su PC local. También debe ejecutarse como un "superusuario" de Postgres (normalmente llamado "root") porque Postgres no puede evitar que haga cosas desagradables con el sistema de archivos local de esa máquina.

En realidad, eso no significa que tenga que estar conectado como superusuario (la automatización sería un riesgo de seguridad de otro tipo), porque puede usar la SECURITY DEFINERopciónCREATE FUNCTION para hacer una función que se ejecute como si fuera un superusuario .

La parte crucial es que su función está allí para realizar comprobaciones adicionales, no solo para evitar la seguridad, por lo que podría escribir una función que exporte los datos exactos que necesita, o podría escribir algo que pueda aceptar varias opciones siempre que cumplir con una estricta lista blanca. Debe verificar dos cosas:

  1. ¿Qué archivos se le debe permitir al usuario leer / escribir en el disco? Este podría ser un directorio en particular, por ejemplo, y el nombre de archivo podría tener un prefijo o extensión adecuados.
  2. ¿Qué tablas debe poder leer / escribir el usuario en la base de datos? Esto normalmente se definiría mediante GRANTs en la base de datos, pero la función ahora se ejecuta como un superusuario, por lo que las tablas que normalmente estarían "fuera de límites" serán completamente accesibles. Probablemente no desee permitir que alguien invoque su función y agregue filas al final de su tabla de "usuarios" ...

He escrito una publicación de blog que amplía este enfoque , incluidos algunos ejemplos de funciones que exportan (o importan) archivos y tablas que cumplen condiciones estrictas.


Lado del cliente

El otro enfoque es manejar los archivos en el lado del cliente , es decir, en su aplicación o script. El servidor de Postgres no necesita saber en qué archivo está copiando, solo escupe los datos y el cliente los coloca en algún lugar.

La sintaxis subyacente para esto es el COPY TO STDOUTcomando, y las herramientas gráficas como pgAdmin lo envolverán en un bonito diálogo.

El psqlcliente de línea de comandos tiene un "metacomando" especial llamado \copy, que toma las mismas opciones que el "real" COPY, pero se ejecuta dentro del cliente:

\copy (Select * From foo) To '/tmp/test.csv' With CSV

Tenga en cuenta que no hay terminación ;, porque los metacomandos terminan con nueva línea, a diferencia de los comandos SQL.

De los documentos :

No confunda COPY con la instrucción psql \ copy. \ copy invoca COPY FROM STDIN o COPY TO STDOUT, y luego recupera / almacena los datos en un archivo accesible para el cliente psql. Por lo tanto, la accesibilidad de los archivos y los derechos de acceso dependen del cliente en lugar del servidor cuando se usa \ copy.

El lenguaje de programación de su aplicación también puede ser compatible con la inserción o recuperación de datos, pero generalmente no puede usar COPY FROM STDIN/ TO STDOUTdentro de una instrucción SQL estándar, porque no hay forma de conectar la secuencia de entrada / salida. El controlador PostgreSQL de PHP ( no PDO) incluye funciones muy básicas pg_copy_fromy pg_copy_toque copian a / desde una matriz PHP, lo que puede no ser eficiente para grandes conjuntos de datos.

IMSoP
fuente
131
Obviamente, el ejemplo anterior requiere a veces que el usuario sea un superusuario, aquí hay una versión para la gente común; psql -o '/tmp/test.csv' database_name
Drachenfels
10
@Drachenfels: también \copyfunciona: allí, las rutas son relativas al cliente y no se necesita / permite ningún punto y coma. Mira mi edición.
krlmlr
3
@IMSoP: ¿Cómo agregaría una instrucción COPY a una función sql (en postgres 9.3)? ¿Entonces la consulta se guarda en un archivo .csv?
jO.
12
Parece que \copydebe ser de una sola línea. Por lo tanto, no tiene la belleza de formatear el sql de la manera que desea, y simplemente poner una copia / función alrededor.
isaaclw
1
@AndreSilva Como dice la respuesta, \copyes un metacomando especial en el psqlcliente de línea de comandos . No funcionará en otros clientes, como pgAdmin; probablemente tendrán sus propias herramientas, como asistentes gráficos, para hacer este trabajo.
IMSoP
519

Hay varias soluciones:

1 psqlcomando

psql -d dbname -t -A -F"," -c "select * from users" > output.csv

Esto tiene la gran ventaja de que puede usarlo a través de SSH, como ssh postgres@host command: le permite obtener

2 copycomandos postgres

COPY (SELECT * from users) To '/tmp/output.csv' With CSV;

3 psql interactivos (o no)

>psql dbname
psql>\f ','
psql>\a
psql>\o '/tmp/output.csv'
psql>SELECT * from users;
psql>\q

Todos pueden usarse en scripts, pero prefiero el n. ° 1.

4 pgadmin pero eso no es programable.

Sorin
fuente
32
En mi humilde opinión, la primera opción es propensa a errores, ya que no incluye el escape adecuado de la coma en los datos exportados.
Piohen
44
Además, psql no cita valores de celda, por lo que si CUALQUIERA de sus datos usa el delimitador, su archivo se dañará.
Cerin
77
@Cerin -t es sinónimo de --tuples-only (apague la impresión de nombres de columnas y pies de página de recuento de resultados, etc.)
omítalo
21
Acabo de probar la afirmación de escape de comas: es cierto, el método 1 no escapa de comas en los valores.
MrColes
1
también use "\ pset footer" para que el recuento de filas no se
acumule
94

En la terminal (mientras está conectado a la base de datos) configure la salida al archivo cvs

1) Configure el separador de campo en ',':

\f ','

2) Establecer el formato de salida sin alinear:

\a

3) Mostrar solo tuplas:

\t

4) Establecer salida:

\o '/tmp/yourOutputFile.csv'

5) Ejecute su consulta:

:select * from YOUR_TABLE

6) Salida:

\o

Luego podrá encontrar su archivo csv en esta ubicación:

cd /tmp

Cópielo con el scpcomando o edite con nano:

nano /tmp/yourOutputFile.csv
Marcin Wasiluk
fuente
44
y \ para volver a imprimir la consola
metdos
2
Esto no producirá un archivo CSV, solo registrará la salida del comando en el archivo de texto (que no lo separa por comas).
Ruslan Kabalin
@RuslanKabalin sí, acabo de notar eso y enmendar las instrucciones para crear resultados separados por comas (cvs)
Marcin Wasiluk
55
Mejoraría esta respuesta al señalar que la salida "csv" no se escapará correctamente y cada vez que se ejecuta un comando sql, los resultados se concatenan en el archivo de salida.
Danny Armstrong
¿Qué pasa con las nuevas líneas en los valores de campo? Los enfoques COPYo \copyse manejan correctamente (convertir a formato CSV estándar); ¿Haz esto?
Comodín el
37

Si está interesado en todas las columnas de una tabla en particular junto con los encabezados, puede usar

COPY table TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

Esto es un poquito más simple que

COPY (SELECT * FROM table) TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

que, que yo sepa, son equivalentes.

benjwadams
fuente
1
Si la consulta es personalizada (es decir, con alias de columna o uniendo tablas diferentes), el encabezado imprimirá los alias de columna tal como se muestran en la pantalla.
Devy
34

CSV Unificación de Exportación

Esta información no está realmente bien representada. Como esta es la segunda vez que necesito derivar esto, lo pondré aquí para recordarme si nada más.

Realmente la mejor manera de hacer esto (sacar CSV de postgres) es usar el COPY ... TO STDOUTcomando. Aunque no desea hacerlo de la manera que se muestra en las respuestas aquí. La forma correcta de usar el comando es:

COPY (select id, name from groups) TO STDOUT WITH CSV HEADER

¡Recuerda solo un comando!

Es genial para usar sobre ssh:

$ ssh psqlserver.example.com 'psql -d mydb "COPY (select id, name from groups) TO STDOUT WITH CSV HEADER"' > groups.csv

Es genial para usar dentro de Docker sobre ssh:

$ ssh pgserver.example.com 'docker exec -tu postgres postgres psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

Incluso es genial en la máquina local:

$ psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

¿O dentro de la ventana acoplable en la máquina local ?:

docker exec -tu postgres postgres psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

¿O en un clúster de kubernetes, en Docker, a través de HTTPS?

kubectl exec -t postgres-2592991581-ws2td 'psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

¡Tan versátil, muchas comas!

¿Por lo menos?

Sí lo hice, aquí están mis notas:

Las COPIAS

Usar /copyefectivamente ejecuta operaciones de archivo en cualquier sistema en el que se psqlesté ejecutando el comando, como el usuario que lo está ejecutando 1 . Si se conecta a un servidor remoto, es simple copiar archivos de datos en el sistema que se ejecuta psqldesde / hacia el servidor remoto.

COPYejecuta operaciones de archivo en el servidor como la cuenta de usuario del proceso de fondo (predeterminado postgres), las rutas de los archivos y los permisos se verifican y aplican en consecuencia. Si se usa, TO STDOUTse omiten las verificaciones de permisos de archivos.

Ambas opciones requieren un movimiento de archivo posterior si psqlno se está ejecutando en el sistema donde desea que resida el CSV resultante. Este es el caso más probable, en mi experiencia, cuando trabajas principalmente con servidores remotos.

Es más complejo configurar algo como un túnel TCP / IP a través de ssh en un sistema remoto para una salida CSV simple, pero para otros formatos de salida (binario) puede ser mejor /copysobre una conexión tunelizada, ejecutando un local psql. De manera similar, para grandes importaciones, mover el archivo fuente al servidor y usarlo COPYes probablemente la opción de mayor rendimiento.

Parámetros de PSQL

Con los parámetros psql puede formatear la salida como CSV pero hay inconvenientes como tener que recordar deshabilitar el localizador y no obtener encabezados:

$ psql -P pager=off -d mydb -t -A -F',' -c 'select * from groups;'
2,Technician,Test 2,,,t,,0,,                                                                                                                                                                   
3,Truck,1,2017-10-02,,t,,0,,                                                                                                                                                                   
4,Truck,2,2017-10-02,,t,,0,,

Otras herramientas

No, solo quiero sacar CSV de mi servidor sin compilar y / o instalar una herramienta.

joshperry
fuente
1
¿Dónde se guardan los resultados? Mi consulta se ejecuta pero el archivo no aparece en ningún lugar de mi computadora. Esto es lo que estoy haciendo: COPIAR (seleccione a, b de c donde d = '1') PARA PARAR CON CSVHEADER> abcd.csv
kRazzy R
1
@kRazzyR La salida va a stdout del comando psql, por lo que, en última instancia, lo que haga con stdout es a dónde van los datos. En mis ejemplos, uso '> file.csv' para redirigir a un archivo. Desea asegurarse de que está fuera del comando que se envía al servidor a través del parámetro psql -c. Vea el ejemplo de 'máquina local'.
joshperry
1
Gracias por la explicación completa. El comando copiar es irremediablemente complejo con psql. Por lo general, termino usando un cliente de base de datos gratuito (dbeaver community edition) para importar y exportar archivos de datos. Proporciona buenas herramientas de mapeo y formateo. Su respuesta proporciona excelentes ejemplos detallados para copiar desde sistemas remotos.
Rich Lysakowski PhD
24

Tuve que usar \ COPY porque recibí el mensaje de error:

ERROR:  could not open file "/filepath/places.csv" for writing: Permission denied

Entonces usé:

\Copy (Select address, zip  From manjadata) To '/filepath/places.csv' With CSV;

y esta funcionando

maudulus
fuente
17

psql puede hacer esto por usted:

edd@ron:~$ psql -d beancounter -t -A -F"," \
                -c "select date, symbol, day_close " \
                   "from stockprices where symbol like 'I%' " \
                   "and date >= '2009-10-02'"
2009-10-02,IBM,119.02
2009-10-02,IEF,92.77
2009-10-02,IEV,37.05
2009-10-02,IJH,66.18
2009-10-02,IJR,50.33
2009-10-02,ILF,42.24
2009-10-02,INTC,18.97
2009-10-02,IP,21.39
edd@ron:~$

Consulte man psqlpara obtener ayuda sobre las opciones utilizadas aquí.

Dirk Eddelbuettel
fuente
12
Este no es un verdadero archivo CSV: mire cómo se quema si hay comas en los datos, por lo que se prefiere usar el soporte de COPIA incorporado. Pero esta técnica general es útil como un truco rápido para exportar desde Postgres en otros formatos delimitados además de CSV.
Greg Smith, el
17

La nueva versión, psql 12, será compatible --csv.

psql - desarrollo

--csv

Cambia al modo de salida CSV (valores separados por comas). Esto es equivalente a \ pset format csv .


csv_fieldsep

Especifica el separador de campo que se utilizará en formato de salida CSV. Si el carácter separador aparece en el valor de un campo, ese campo se genera entre comillas dobles, siguiendo las reglas CSV estándar. El valor predeterminado es una coma.

Uso:

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv -P csv_fieldsep='^'  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres > output.csv
Lukasz Szozda
fuente
16

Estoy trabajando en AWS Redshift, que no es compatible con la COPY TOfunción.

Sin embargo, mi herramienta de BI admite CSV delimitados por tabulaciones, por lo que utilicé lo siguiente:

 psql -h dblocation -p port -U user -d dbname -F $'\t' --no-align -c "SELECT * FROM TABLE" > outfile.csv
calcsam
fuente
11

En pgAdmin III hay una opción para exportar a un archivo desde la ventana de consulta. En el menú principal es Consulta -> Ejecutar para archivar o hay un botón que hace lo mismo (es un triángulo verde con un disquete azul en lugar del triángulo verde que simplemente ejecuta la consulta). Si no está ejecutando la consulta desde la ventana de consulta, entonces haría lo que IMSoP sugirió y usaría el comando copiar.

Amanda Nyren
fuente
La respuesta de IMSoP no funcionó para mí, ya que necesitaba ser un súper administrador. Esto funcionó de maravilla. ¡Gracias!
Mike
9

Intenté varias cosas, pero pocas pudieron darme el CSV deseado con los detalles del encabezado.

Esto es lo que funcionó para mí.

psql -d dbame -U username \
  -c "COPY ( SELECT * FROM TABLE ) TO STDOUT WITH CSV HEADER " > \
  OUTPUT_CSV_FILE.csv
pyAddict
fuente
9

He escrito una pequeña herramienta llamada psql2csvque encapsula el COPY query TO STDOUTpatrón, lo que resulta en un CSV adecuado. Su interfaz es similar a psql.

psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY

Se supone que la consulta es el contenido de STDIN, si está presente, o el último argumento. Todos los demás argumentos se envían a psql excepto estos:

-h, --help           show help, then exit
--encoding=ENCODING  use a different encoding than UTF8 (Excel likes LATIN1)
--no-header          do not output a header
fphilipe
fuente
2
Funciona genial. Gracias.
AlexM
6

Si tiene una consulta más larga y le gusta usar psql, coloque su consulta en un archivo y use el siguiente comando:

psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv
Andres Kull
fuente
FWIW, tuve que usar en -F","lugar de -F";"generar un archivo CSV que se abriría correctamente en MS Excel
CFL_Jeff
4

Para descargar el archivo CSV con nombres de columna como HEADER, use este comando:

Copy (Select * From tableName) To '/tmp/fileName.csv' With CSV HEADER;
murli
fuente
1

Recomiendo encarecidamente DataGrip , una base de datos IDE de JetBrains. Puede exportar una consulta SQL a un archivo CSV y puede configurar túneles ssh con facilidad. Cuando la documentación se refiere al "conjunto de resultados", significan el resultado devuelto por una consulta SQL en la consola.

No estoy asociado con DataGrip, ¡me encanta el producto!

skeller88
fuente
Supongo que el voto negativo se debió a una falta de contexto / explicación, por lo que me he vinculado a la documentación de DataGrip. Si hay una razón diferente para el voto negativo, hágamelo saber. He usado las soluciones CLI anteriores y DataGrip es mucho más fácil para consultas más pequeñas.
skeller88
El problema con DataGrip es que controla tu billetera. No es gratis Pruebe la edición comunitaria de DBeaver en dbeaver.io . Es una herramienta de base de datos multiplataforma FOSS para programadores SQL, DBA y analistas que admite todas las bases de datos populares: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc.
Rich Lysakowski PhD
Genial, lo comprobaré. ¿Qué tal si vuelves a publicar tu comentario como respuesta también?
skeller88
0

JackDB , un cliente de base de datos en su navegador web, lo hace realmente fácil. Especialmente si estás en Heroku.

Le permite conectarse a bases de datos remotas y ejecutar consultas SQL en ellas.

                                                                                                                                                       Fuente (fuente: jackdb.com )jackdb-heroku


Una vez que su base de datos está conectada, puede ejecutar una consulta y exportar a CSV o TXT (ver abajo a la derecha).


jackdb-export

Nota: de ninguna manera estoy afiliado a JackDB. Actualmente uso sus servicios gratuitos y creo que es un gran producto.

Dennis
fuente
0

Por solicitud de @ skeller88, estoy volviendo a publicar mi comentario como respuesta para que las personas que no leen cada respuesta no lo pierdan ...

El problema con DataGrip es que controla tu billetera. No es gratis Pruebe la edición comunitaria de DBeaver en dbeaver.io. Es una herramienta de base de datos multiplataforma FOSS para programadores SQL, DBA y analistas que admite todas las bases de datos populares: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc.

DBeaver Community Edition hace que sea trivial conectarse a una base de datos, realizar consultas para recuperar datos y luego descargar el conjunto de resultados para guardarlo en CSV, JSON, SQL u otros formatos de datos comunes. Es un competidor viable de FOSS para TOAD para Postgres, TOAD para SQL Server o Toad para Oracle.

No tengo afiliación con DBeaver. Me encanta el precio y la funcionalidad, pero desearía que abrieran más la aplicación DBeaver / Eclipse y facilitaran la adición de widgets de análisis a DBeaver / Eclipse, en lugar de exigir a los usuarios que paguen la suscripción anual para crear gráficos y tablas directamente en la aplicación. Mis habilidades de codificación Java están oxidadas y no tengo ganas de tomarme semanas para volver a aprender cómo construir widgets de Eclipse, solo para descubrir que DBeaver ha deshabilitado la capacidad de agregar widgets de terceros a DBeaver Community Edition.

¿Los usuarios de DBeaver tienen una idea de los pasos para crear widgets de análisis para agregar a la edición comunitaria de DBeaver?

Rich Lysakowski PhD
fuente
-3
import json
cursor = conn.cursor()
qry = """ SELECT details FROM test_csvfile """ 
cursor.execute(qry)
rows = cursor.fetchall()

value = json.dumps(rows)

with open("/home/asha/Desktop/Income_output.json","w+") as f:
    f.write(value)
print 'Saved to File Successfully'
usuario9279273
fuente
3
Explique lo que hizo editando la respuesta, evite la respuesta de solo código
GGO
3
Gracias por este fragmento de código, que podría proporcionar una ayuda limitada a corto plazo. Una explicación adecuada mejoraría en gran medida su valor a largo plazo al mostrar por qué esta es una buena solución al problema y la haría más útil para futuros lectores con otras preguntas similares. Por favor, editar su respuesta a añadir un poco de explicación, incluyendo los supuestos realizados.
Toby Speight
2
Esto producirá un archivo json, no un archivo csv.
nvoigt