【问题标题】:Postgres CSV COPY from/import is not respecting CSV headersPostgres CSV COPY from/import 不尊重 CSV 标头
【发布时间】:2015-10-22 00:15:21
【问题描述】:

我正在尝试将数据从 CSV 导入表中。问题是即使使用CSV HEADER,CSV 也是基于列索引导入的,而不是基于该列的标题。

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
);

我的 CSV 文件如下所示:

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,

我的 COPY 命令在 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;"

我得到的错误是:

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

现在,我要重新排列 CSV 中的列,但这不应该可行吗?

【问题讨论】:

    标签: postgresql csv


    【解决方案1】:

    COPY 命令默认按照表中列的默认顺序从 CSV 文件中复制列。 HEADER 选项on input is ignored,它基本上只通知后端忽略输入的第一行。如果 CSV 中的列顺序与表中的列顺序不匹配,可以显式指定列顺序以匹配 CSV 文件的布局:

    COPY churches (id,denomination_id,name,address_id)
    FROM '$PWD/data/Data - Churches.csv'
    WITH DELIMITER ',' CSV HEADER;
    

    【讨论】:

    • 哦。该死的。希望它更加自动化。谢谢
    • 嗯,这对我来说看起来是多才多艺的。只需将标题行复制到 COPY 命令即可。用任何体面的语言甚至是手写都可以轻松完成。
    • 哦,聪明!我怎么能在 bash 中做到这一点?
    • 嗯,不是 bash 专家,但读取 CSV 文件直到 \n 以获取标题行,然后将该值粘贴到 COPY 命令中。例如head -n 1 _filename_.
    • COPY 命令还有很大的改进空间,自动标头识别会很好。据我所知,没有人在做这件事。大多数需要做更有趣的事情的人都使用 ETL 工具。
    【解决方案2】:

    这是一个使用 csv 标题行导入用户的单行示例:

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

    或使用 gzip:

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

    【讨论】:

    • 这个答案正是医生要求的
    【解决方案3】:

    只是为了在接受的答案下回答 Jonathan 的评论 - 如果您想从“尊重”列顺序的 CSV 加载数据(我有一些具有不同架构迁移历史的转储,或者缺少我想导入的列) .

    如果您想使用 CSV 标头将其导入 Bash: (我的表名是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
    

    【讨论】:

      猜你喜欢
      • 2013-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多