21

I'm trying to import data from CSV into the table. The issue is that even with CSV HEADER, the CSV is being imported based on the column index, not on the headers of that column.

CREATE TABLE denominations (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);

CREATE TABLE churches (
  id SERIAL PRIMARY KEY,
  -- NOT relevant here
  address_id INTEGER REFERENCES addresses,
  denomination_id INTEGER NOT NULL REFERENCES denominations,
  name VARCHAR(100) NOT NULL
);

My CSVs look like:

id,name
1,Southern Baptist Convention
2,Nondenominational
3,Catholic
4,Presbyterian


id,denomination_id,name,address_id
1,1,Saddleback Church,
2,4,First Presbyterian Church,
3,3,St. Elizabeth's Church,
4,3,St Monica Catholic Community,
5,2,Modern Day Saints Church,
6,4,Second Presbyterian Church,

My COPY command looks like this in bash:

psql -d vacation -c "COPY denominations FROM '$PWD/data/Data - Denominations.csv' WITH DELIMITER ',' CSV HEADER;"
psql -d vacation -c "COPY churches FROM '$PWD/data/Data - Churches.csv' WITH DELIMITER ',' CSV HEADER;"

The error I get is:

ERROR:  invalid input syntax for integer: "Saddleback Church"
CONTEXT:  COPY churches, line 2, column denomination_id: "Saddleback Church"

For now, I'm going to rearrange the columns in the CSV, but shouldn't this work?

0

3 Answers 3

32

The COPY command by default copies columns from a CSV file in the default order of the columns in the table. The HEADER option on input is ignored, it basically only informs the backend to ignore the first line on input. If the order of the columns in the CSV does not match the order of the columns in the table, you can explicitly specify the column order to match the layout of the CSV file:

COPY churches (id,denomination_id,name,address_id)
FROM '$PWD/data/Data - Churches.csv'
WITH DELIMITER ',' CSV HEADER;
Sign up to request clarification or add additional context in comments.

8 Comments

ohhhh. damnit. was hoping it was more automated. thanks
Well, this looks as versatile to me as it gets. Simply copy your header line to the COPY command. Easy-peasy in any decent language or even by hand.
oh, smart! how can i do that in bash?
uhm, no expert in bash, but read the CSV file up to \n to get your header line, then paste that value into the COPY command. For instance with head -n 1 _filename_.
There's lots of room for improvement in the COPY command, and automatic header recognition would be nice. Nobody's working on it as far as I know. Most people who need to do fancier stuff use ETL tools.
|
11

Here's a single line example for importing users using the header row of a csv:

echo "\copy users ($(head -1 users.csv)) FROM 'users.csv' DELIMITER ',' CSV HEADER" | psql

Or with gzip:

echo "\copy users ($(gzip -dc users.csv.gz | head -1)) FROM PROGRAM 'gzip -dc users.csv.gz' DELIMITER ',' CSV HEADER" | psql

1 Comment

This answer is just what the doctor ordered
2

Just to answer Jonathan's comment under the accepted answer - if you want to load the data from CSV "respecting" the column order (I had a few dumps with different schema migration history, or missing columns, which I wanted to import).

If you want to use the CSV headers to import it in Bash: (my table's name is alarms)

#!/bin/bash

if [ -z "$1" ] ; then
    echo "Usage: $0 <alarms_dump_file.csv>"
    exit
fi

columns=$(head -n1 $1)
echo "Using columns:"
if ! echo $columns | grep '^id,' ; then
    echo "Missing id in header. No header present? See below:"
    echo $columns
    exit
fi

sudo -u postgres psql YOUR_DATABASE <<EOF
\copy alarms ( $columns ) FROM '$1' DELIMITER ',' CSV HEADER;
EOF

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.