Postgres \copy from stdin vs pstdin

2015-02-14

Sometimes in Postgres you want to initialize a table by reading a bunch of data from stdin, like this:

psql "$database" -f init.sql < /usr/share/dict/american-english

using an init.sql like this:

DROP TABLE IF EXISTS dictionary;
CREATE TABLE dictionary (id SERIAL PRIMARY KEY, word VARCHAR NOT NULL);
\copy dictionary (word) from stdin
CREATE UNIQUE INDEX idx_dictionary_word ON dictionary (word);

The problem is that with the -f flag, psql ignores its stdin and treats the file you name with -f as if it were stdin. So running the above would add just one word to your database, spelled “CREATE UNIQUE INDEX …”.

The solution to this is to use \copy dictionary (word) from pstdin instead. That tells psql to copy from its real stdin rather than from the -f file.

As far as I know there is no way to do this using COPY FROM rather than \copy from if you want COPY FROM to appear inside a larger .sql file. So this works:

psql "$database" -c "COPY dictionary (word) FROM STDIN" < /usr/share/dict/american-english

but this does not:

psql "$database" -f init.sql < /usr/share/dict/american-english

and neither does this:

psql "$database" -c '\i init.sql' < /usr/share/dict/american-english

But I’d love to be corrected if someone knows a way!

blog comments powered by Disqus Prev: Postgres LATERAL JOIN Next: Rails acts_as_list with Soft Delete