Postgres: \copy syntax - postgresql

With PostgreSQL 9.5 on CentOS 7, I have created a database named sample along with several tables. I have .csv data in /home/MyUser/data for each table.
For example, there exists TableName.csv for the table "TableName".
How do I load the csv files into each table?
What I've tried doesn't work and I can't figure out what I'm doing wrong.
Load from within the DB
$ psql sample
sample=# COPY "TableName" FROM '/home/MyUser/data/TableName.csv' WITH CSV;
ERROR: could not open file "/home/MyUser/data/TableName.csv" for reading: Permission denied
This implies a file permission problem. All the files in data/ are -rw-r--r-- and the directory itself is drwxr-xr-x. So file permissions shouldn't be the problem (unless I'm missing something). The internet says that COPY has problems with permissions and to try \copy.
Load from CLI
$ psql \copy sample FROM /home/MyUser/data/TableName.csv WITH CSV
psql: warning: extra command-line argument "FROM" ignored
psql: warning: extra command-line argument "/home/MyUser/data/TableName.csv" ignored
psql: warning: extra command-line argument "WITH" ignored
psql: warning: extra command-line argument "CSV" ignored
psql: FATAL: Peer authentication failed for user "sample"
This appears to be a syntax error, but I'm not finding the documentation particularly helpful (man psql then /\copy). I've also tried the following to the same result.
$ psql \copy sample."TableName" FROM /home/MyUser/data/TableName.csv WITH CSV
$ psql \copy sample FROM /home/MyUser/data/TableName.csv WITH DELIMITER ','
There are several other permutations which yield similar errors.
Web Resources Used
https://www.postgresql.org/docs/9.5/static/app-psql.html
https://www.postgresql.org/docs/9.5/static/sql-copy.html
The correct COPY command to load postgreSQL data from csv file that has single-quoted data?
https://soleil4716.wordpress.com/2010/08/19/using-copy-command-in-postgresql/
Can I use \copy command into a function of postgresql?
https://wiki.postgresql.org/wiki/COPY

About the permissions:
Don't forget that to access a file you need permissions on all directories in the path. So if, for example, the OS user postgres does not have permissions on the /home/MyUser directory, you get the observed error message.
About \copy:
You have to use the -c option to supply a command to psql:
$ psql -c "\copy sample FROM '/home/MyUser/data/TableName.csv' WITH (FORMAT CSV)"

Adding, this sample was helpful from Laurenz, as I got this to work first time today from a windows 10 client.
My target is an enterprise greenplum db (same thing just parallel/scale).
Step 1, Postgres client installed (I didn't install the database itself, but all the other items as part of the windows bundling install, including the shell most importantly for this)
https://www.postgresql.org/download/
Step 2, Create your target table on your workspace/db. I use DBeaver to connect to greenplum db, then run this, you don't have to use DBeaver, you can probably run this in the shell itself.
CREATE TABLE workspacename.scott_test2 (
blah1 varchar(40) NOT NULL,
blah2 varchar(40) NOT NULL
)
DISTRIBUTED BY (blah1);
Step 3, launch the shell command from postgres utilities installed earlier, login as it prompts you, then when you're in, the command I ran in that shell installed above (a command line interface) is simply:
\copy workspacename.scott_test2 FROM 'C:\temp\flatfile.csv' WITH CSV;
Note \copy is not copy. Use \copy
This loaded a half million row table in 2 seconds, fast. file above is comma delimited, the with CSV does that.

Related

Importing a CSV file into postgres. Error: No such file or directory

I'm trying to import a CSV file into postgresql database.
First of all I tried following query:
copy temporaryData
from '/home/milad/Desktop/myFolder/csvFiles/test.csv'
delimiter ',' csv;
But it gave me below Error:
SQL Error [42501]: ERROR: could not open file "/home/milad/Desktop/myFolder/test.csv" for reading: Permission denied
This error is reasonable as suggested by this thread and also by postgresql tutorial:
Notice that the file must be read directly by the PostgreSQL server, not by the client application. Therefore, it must be accessible by the PostgreSQL server machine. Also, you need to have superuser access in order to execute the COPY statement successfully.
Since I don't like to change my system permissions just to import a file, To solve this issue I decided to move my CSV file to /tmp/ directory which is suggested by this answer.
Then I tried to run below script:
create or replace procedure loadInstructorOfCourses()
language plpgsql
as $$
begin
create table temporaryData(
courseSectionID varchar(10),
instructorID varchar(25),
courseTitle varchar(50)
);
copy temporaryData
from '/tmp/test.csv'
delimiter ',' csv;
drop table temporaryData;
end;$$;
call loadInstructorOfCourses();
And now it gives me below error:
SQL Error [58P01]: ERROR: could not open file "/tmp/test.csv" for reading: No such file or directory
But I'm sure the file has read permission for others and also it's available:
> ls -l -d /tmp
drwxrwxrwt 25 root root 700 Oct 20 09:53 /tmp
> ls -l /tmp/test.csv
-rw-r--r-- 1 milad milad 6700 Oct 20 09:53 /tmp/test.csv
Why does this problem happen and how to resolve it?
INFO:
My OS is Manjaro KDE:
> uname -r
5.4.150-1-MANJARO
And also I use DBeaver to connect to postgresql server and run my scripts.
UPDATES: Using psql I have the same issue too. When I connect to db by psql:
psql -U postgres -d IUTPlanning
and run my procedure:
call loadInstructorOfCourses();
I'll get the same error:
ERROR: could not open file "/tmp/test.csv" for reading: No such file or directory
HINT: COPY FROM instructs the PostgreSQL server process to read a file. You may want a client-side facility such as psql's \copy.
CONTEXT: SQL statement "copy temporaryData
from '/tmp/test.csv'
delimiter ',' csv"
PL/pgSQL function loadinstructorofcourses() line 9 at SQL statement
Try using psql's \copy command, as the hint in the error message you quoted suggests. COPY FROM tells the server to open the file and process it, while \copy reads the file client side and then passes the output to the server, see https://stackoverflow.com/a/19466558/12760895
Open the psql console with psql -U postgres -d [yourdb]
then run
\copy [target_table] from '/tmp/test.csv' DELIMITER ',' CSV;

How to export all tables in a PostgreSQL database to csv files?

I went to the psql commandline mode and entered the correct database and I can list all the tables.
Now, I tried the following commands:
copy some_table_name1 to '/var/lib/pgsql/csv_exports/some_table_name1.csv' csv header
copy some_table_name2 to '/var/lib/pgsql/csv_exports/some_table_name2.csv' csv header
And so on...
There was no error messages or anything after the commands and I used tab-button to ensure that I was always referring to correct table names.
After doing this to all the tables I went to the directory and there were no files at all.
Am I doing something wrong?
EDIT: I should clarify that I was looking to that directory, by using putty and WINSCP, on the server machine. The same where I ran the psql commands in.
The files are written to that directory on the server machine, not the client.
Use COPY ... TO STDOUT to send the data to the client.
Using psql in the console you can use the following command to get your data in the client machine:
$ psql yourdb -c "COPY yourtable TO STDOUT DELIMITER ',' CSV HEADER" > output.csv
If you're wondering about how to do the other way around (import), take a look at this question.
Assuming that what you really want to do is to output the file to someplace on your local machine (ie your developer workstation), I suggest that you use the "\copy" command, instead of the "COPY" command.
psql -c "\copy (SELECT * FROM account) to '/tmp/account.csv' with csv;"
or
psql -c "\copy account TO '/tmp/account.csv' DELIMITER ',' CSV HEADER;
Otherwise, unless you explicitly redirect the command to stdout, as #LaurenzAlbe suggested, the "COPY"command will check and see if you are authorized to write the files out to the actual database server. Normally, this is not the behavior that you and, and it requires accesses and permissions greater than most developers have.

Restore one table from a database in PostgreSQL and save it with plain/text data format

I have a table (tst2) in a database (tweets) in PostgreSQL and I need to have a plain/text format file out of it, I was wondering if there is any possible solution with pg_dump ? something like :
pg_dump -t tst2 tweets -f plain >...
also if I am in a wrong way please let me know?!
There are a couple of ways to dump a table into a text file.
First, you can use pg_dump, as you intended. In that case you'll get a SQL script to restore the tables. Just fix your command a bit:
pg_dump -t tst2 -t tweets -F plain >...
Second, you can dump contents of a table with copy command. There are either SQL version of the command (files will be created on the server):
copy tst2 to 'tst2.txt';
copy tweets to 'tweets.txt';
Or client-side psql version (files will be created on your client computer):
\copy tst2 to 'tst2.txt';
\copy tweets to 'tweets.txt';
pg_dump works for me, though there is some clutter before and after the table (after all, dumps are supposed to be used to fill up the table at recovery time).
I'm not sure what you use the > operator for; the dump goes to the file `plane'.
Your error message would help, of course.
On the other hand, what's wrong with using psql with a .pgpass password file and setting the PGDATABASE, PGHOST, PGPORT, and PGUSER anvironment variables, e.g.:
export PGDATABASE=tweet
# PGHOST, PGPORT, and PGUSER as per your setup
psql -c 'select * from tst2'

Is it possible to convert a psql's ASCII table output to CSV? [duplicate]

What is the easiest way to save PL/pgSQL output from a PostgreSQL database to a CSV file?
I'm using PostgreSQL 8.4 with pgAdmin III and PSQL plugin where I run queries from.
Do you want the resulting file on the server, or on the client?
Server side
If you want something easy to re-use or automate, you can use Postgresql's built in COPY command. e.g.
Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER;
This approach runs entirely on the remote server - it can't write to your local PC. It also needs to be run as a Postgres "superuser" (normally called "root") because Postgres can't stop it doing nasty things with that machine's local filesystem.
That doesn't actually mean you have to be connected as a superuser (automating that would be a security risk of a different kind), because you can use the SECURITY DEFINER option to CREATE FUNCTION to make a function which runs as though you were a superuser.
The crucial part is that your function is there to perform additional checks, not just by-pass the security - so you could write a function which exports the exact data you need, or you could write something which can accept various options as long as they meet a strict whitelist. You need to check two things:
Which files should the user be allowed to read/write on disk? This might be a particular directory, for instance, and the filename might have to have a suitable prefix or extension.
Which tables should the user be able to read/write in the database? This would normally be defined by GRANTs in the database, but the function is now running as a superuser, so tables which would normally be "out of bounds" will be fully accessible. You probably don’t want to let someone invoke your function and add rows on the end of your “users” table…
I've written a blog post expanding on this approach, including some examples of functions that export (or import) files and tables meeting strict conditions.
Client side
The other approach is to do the file handling on the client side, i.e. in your application or script. The Postgres server doesn't need to know what file you're copying to, it just spits out the data and the client puts it somewhere.
The underlying syntax for this is the COPY TO STDOUT command, and graphical tools like pgAdmin will wrap it for you in a nice dialog.
The psql command-line client has a special "meta-command" called \copy, which takes all the same options as the "real" COPY, but is run inside the client:
\copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER
Note that there is no terminating ;, because meta-commands are terminated by newline, unlike SQL commands.
From the docs:
Do not confuse COPY with the psql instruction \copy. \copy invokes COPY FROM STDIN or COPY TO STDOUT, and then fetches/stores the data in a file accessible to the psql client. Thus, file accessibility and access rights depend on the client rather than the server when \copy is used.
Your application programming language may also have support for pushing or fetching the data, but you cannot generally use COPY FROM STDIN/TO STDOUT within a standard SQL statement, because there is no way of connecting the input/output stream. PHP's PostgreSQL handler (not PDO) includes very basic pg_copy_from and pg_copy_to functions which copy to/from a PHP array, which may not be efficient for large data sets.
There are several solutions:
1 psql command
psql -d dbname -t -A -F"," -c "select * from users" > output.csv
This has the big advantage that you can using it via SSH, like ssh postgres#host command - enabling you to get
2 postgres copy command
COPY (SELECT * from users) To '/tmp/output.csv' With CSV;
3 psql interactive (or not)
>psql dbname
psql>\f ','
psql>\a
psql>\o '/tmp/output.csv'
psql>SELECT * from users;
psql>\q
All of them can be used in scripts, but I prefer #1.
4 pgadmin but that's not scriptable.
In terminal (while connected to the db) set output to the cvs file
1) Set field seperator to ',':
\f ','
2) Set output format unaligned:
\a
3) Show only tuples:
\t
4) Set output:
\o '/tmp/yourOutputFile.csv'
5) Execute your query:
:select * from YOUR_TABLE
6) Output:
\o
You will then be able to find your csv file in this location:
cd /tmp
Copy it using the scp command or edit using nano:
nano /tmp/yourOutputFile.csv
CSV Export Unification
This information isn't really well represented. As this is the second time I've needed to derive this, I'll put this here to remind myself if nothing else.
Really the best way to do this (get CSV out of postgres) is to use the COPY ... TO STDOUT command. Though you don't want to do it the way shown in the answers here. The correct way to use the command is:
COPY (select id, name from groups) TO STDOUT WITH CSV HEADER
Remember just one command!
It's great for use over ssh:
$ ssh psqlserver.example.com 'psql -d mydb "COPY (select id, name from groups) TO STDOUT WITH CSV HEADER"' > groups.csv
It's great for use inside docker over ssh:
$ ssh pgserver.example.com 'docker exec -tu postgres postgres psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv
It's even great on the local machine:
$ psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv
Or inside docker on the local machine?:
docker exec -tu postgres postgres psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv
Or on a kubernetes cluster, in docker, over HTTPS??:
kubectl exec -t postgres-2592991581-ws2td 'psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv
So versatile, much commas!
Do you even?
Yes I did, here are my notes:
The COPYses
Using /copy effectively executes file operations on whatever system the psql command is running on, as the user who is executing it1. If you connect to a remote server, it's simple to copy data files on the system executing psql to/from the remote server.
COPY executes file operations on the server as the backend process user account (default postgres), file paths and permissions are checked and applied accordingly. If using TO STDOUT then file permissions checks are bypassed.
Both of these options require subsequent file movement if psql is not executing on the system where you want the resultant CSV to ultimately reside. This is the most likely case, in my experience, when you mostly work with remote servers.
It is more complex to configure something like a TCP/IP tunnel over ssh to a remote system for simple CSV output, but for other output formats (binary) it may be better to /copy over a tunneled connection, executing a local psql. In a similar vein, for large imports, moving the source file to the server and using COPY is probably the highest-performance option.
PSQL Parameters
With psql parameters you can format the output like CSV but there are downsides like having to remember to disable the pager and not getting headers:
$ 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,,
Other Tools
No, I just want to get CSV out of my server without compiling and/or installing a tool.
New version - psql 12 - will support --csv.
psql - devel
--csv
Switches to CSV (Comma-Separated Values) output mode. This is equivalent to \pset format csv.
csv_fieldsep
Specifies the field separator to be used in CSV output format. If the separator character appears in a field's value, that field is output within double quotes, following standard CSV rules. The default is a comma.
Usage:
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
If you're interested in all the columns of a particular table along with headers, you can use
COPY table TO '/some_destdir/mycsv.csv' WITH CSV HEADER;
This is a tiny bit simpler than
COPY (SELECT * FROM table) TO '/some_destdir/mycsv.csv' WITH CSV HEADER;
which, to the best of my knowledge, are equivalent.
I had to use the \COPY because I received the error message:
ERROR: could not open file "/filepath/places.csv" for writing: Permission denied
So I used:
\Copy (Select address, zip From manjadata) To '/filepath/places.csv' With CSV;
and it is functioning
psql can do this for you:
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:~$
See man psql for help on the options used here.
I'm working on AWS Redshift, which does not support the COPY TO feature.
My BI tool supports tab-delimited CSVs though, so I used the following:
psql -h dblocation -p port -U user -d dbname -F $'\t' --no-align -c "SELECT * FROM TABLE" > outfile.csv
In pgAdmin III there is an option to export to file from the query window. In the main menu it's Query -> Execute to file or there's a button that does the same thing (it's a green triangle with a blue floppy disk as opposed to the plain green triangle which just runs the query). If you're not running the query from the query window then I'd do what IMSoP suggested and use the copy command.
I tried several things but few of them were able to give me the desired CSV with header details.
Here is what worked for me.
psql -d dbame -U username \
-c "COPY ( SELECT * FROM TABLE ) TO STDOUT WITH CSV HEADER " > \
OUTPUT_CSV_FILE.csv
I've written a little tool called psql2csv that encapsulates the COPY query TO STDOUT pattern, resulting in proper CSV. It's interface is similar to psql.
psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY
The query is assumed to be the contents of STDIN, if present, or the last argument. All other arguments are forwarded to psql except for these:
-h, --help show help, then exit
--encoding=ENCODING use a different encoding than UTF8 (Excel likes LATIN1)
--no-header do not output a header
If you have longer query and you like to use psql then put your query to a file and use the following command:
psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv
To Download CSV file with column names as HEADER use this command:
Copy (Select * From tableName) To '/tmp/fileName.csv' With CSV HEADER;
Since Postgres 12, you can change the output format :
\pset format csv
The following formats are allowed :
aligned, asciidoc, csv, html, latex, latex-longtable, troff-ms, unaligned, wrapped
If you want to export the result of a request, you can use the \o filename feature.
Example :
\pset format csv
\o file.csv
SELECT * FROM table LIMIT 10;
\o
\pset format aligned
I found that psql --csv creates a CSV file with UTF8 characters but it is missing the UTF8 Byte Order Mark (0xEF 0xBB 0xBF). Without taking it into account, the default import of this CSV file will corrupt international characters such as CJK characters.
To fix it, I devised the following script:
# Define a connection to the Postgres database through environment variables
export PGHOST=your.pg.host
export PGPORT=5432
export PGDATABASE=your_pg_database
export PGUSER=your_pg_user
# Place credentials in $HOME/.pgpass with the format:
# ${PGHOST}:${PGPORT}:${PGUSER}:master:${PGPASSWORD}
# Populate long SQL query in a text file:
cat > /tmp/query.sql <<EOF
SELECT item.item_no,item_descrip,
invoice.invoice_no,invoice.sold_qty
FROM item
LEFT JOIN invoice
ON item.item_no=invoice.item_no;
EOF
# Generate CSV report with UTF8 BOM mark
printf '\xEF\xBB\xBF' > report.csv
psql -f /tmp/query.sql --csv | tee -a report.csv
Doing it this way, lets me script the CSV creation process for automation and allows me to succinctly maintain the script in a single source file.
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'
JackDB, a database client in your web browser, makes this really easy. Especially if you're on Heroku.
It lets you connect to remote databases and run SQL queries on them.
Source
(source: jackdb.com)
Once your DB is connected, you can run a query and export to CSV or TXT (see bottom right).
Note: I'm in no way affiliated with JackDB. I currently use their free services and think it's a great product.
Per the request of #skeller88, I am reposting my comment as an answer so that it doesn't get lost by people who don't read every response...
The problem with DataGrip is that it puts a grip on your wallet. It is not free. Try the community edition of DBeaver at dbeaver.io. It is a FOSS multi-platform database tool for SQL programmers, DBAs and analysts that supports all popular databases: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc.
DBeaver Community Edition makes it trivial to connect to a database, issue queries to retrieve data, and then download the result set to save it to CSV, JSON, SQL, or other common data formats. It's a viable FOSS competitor to TOAD for Postgres, TOAD for SQL Server, or Toad for Oracle.
I have no affiliation with DBeaver. I love the price and functionality, but I wish they would open up the DBeaver/Eclipse application more and made it easy to add analytics widgets to DBeaver / Eclipse, rather than requiring users to pay for the annual subscription to create graphs and charts directly within the application. My Java coding skills are rusty and I don't feel like taking weeks to relearn how to build Eclipse widgets, only to find that DBeaver has disabled the ability to add third-party widgets to the DBeaver Community Edition.
Do DBeaver users have insight as to the steps to create analytics widgets to add into the Community Edition of DBeaver?

How can I use DBI to execute a "\copy from remote table" command in Postgres?

I need to copy from a remote PostgreSQL server to a local one. I cannot use any ETL tools, it must be done using Perl with DBI. This data will be large, so I don't want to use "select from source" and "insert into local". I was looking to use COPY to create a file, but this file will be created on the remote server. I can't do that either. I want to use \COPY instead.
How can I use DBI to execute a "\copy from remote table" command and create a local file using DBI in Perl?
You can do it in perl with DBD::Pg, details can be found here:
https://metacpan.org/pod/DBD::Pg#COPY-support
You definitely want to use the "copy from" and "copy to" commands to get the data in and out of the databases efficiently. They are orders of magnitude faster than iterating over rows of data. You many also want to turn off the indexes while you're copying data into the target table, then enable them (and let them build) when the copy is complete.
Assuming you are simply connecting to the listener ports of the two databases, simply open a connection to the source database, copy the table(s) to a file, open a connection to the destination database and copy the file back to the target table.
Hmm. \copy to ... is a psql directive, not SQL, so it won't be understood by DBI or by the PostgreSQL server at the other end.
I see that the PostgreSQL's SQL COPY command has FROM STDIN and TO STDOUT options -- but I doubt that DBI has a way to perform the "raw reads" necessary to access the result data. (I'm sure TO STDOUT is how psql internally implements \copy to ....)
So: In your case, I would mount a folder on your source box back to your target box using e.g. samba or nfs, and use plain old COPY TO '/full/path/to/mounted/folder/data.txt' ....
I got it to work using \copy (select * from remote_table) to '/local/file.txt' ... then \copy local_table from '/local/file.txt' to load the file into the local db. I executed the \copy command from a psql script.
Here's my script
export PGUSER=remoteuser
export PGPASSWORD=remotepwd
/opt/PostgreSQL/8.3/bin/psql -h xx.xx.xx -p 5432 -d remotedb -c "\COPY (select * from remote_table where date(reccreationtim
e) = date((current_date - interval '4 day'))) TO '/local/copied_from_remote.txt' D
ELIMITER '|'"
export PGUSER=localuser
export PGPASSWORD=localpwd
/opt/PostgreSQL/8.3/bin/psql -h xx.xx.xx.xx -p 5432 -d localdb -c "\COPY local_table FROM '/local/copied_from_remote.txt' DELIMITER '|'"
You could use ~/.pgpass and save yourself the export PGUSER stuff, and keep the password out of the environment... (always a good idea from a security perspective)