如何将 CSV 复制为 JSON 字段

Pet*_*uss 3 csv postgresql jsonb

有没有办法将 CSV 文件数据直接复制到 JSON 或 JSONb 数组中?

例子:

CREATE TABLE mytable (
    id serial PRIMARY KEY,
    info jSONb -- or JSON
);
COPY mytable(info) FROM '/tmp/myfile.csv' HEADER csv;
Run Code Online (Sandbox Code Playgroud)

注意:每个 CSV 行都映射到一个 JSON 数组。这是一个普通的CSV。


普通 CSV(没有嵌入 JSON)... /tmp/myfile.csv=

a,b,c
100,Mum,Dad
200,Hello,Bye
Run Code Online (Sandbox Code Playgroud)

正确的 COPY 命令必须等同于通常的复制波纹管。

通常的 COPY(丑陋但工作正常)

CREATE TEMPORARY TABLE temp1 (
  a int, b text, c text
);
COPY temp1(a,b,c) FROM '/tmp/myfile.csv' HEADER csv;

INSERT INTO mytable(info) SELECT json_build_array(a,b,c) FROM temp1;
Run Code Online (Sandbox Code Playgroud)

很丑,因为:

  • 需要一个修道院有关领域的知识,和以前CREATE TABLE用它。

  • “大数据”需要一个大的临时表,因此丢失了 CPU、磁盘和我的时间——该表mytable的每一行都有 CHECK 和 UNIQUEs 约束。

  • ... 需要 1 个以上的 SQL 命令。

Pet*_*uss 5

完美解决!

不需要知道所有的 CSV 列,只提取你知道的。

在 SQL 中使用CREATE EXTENSION PLpythonU;:如果该命令产生“无法打开扩展控制文件...没有这样的文件”之类的错误,则需要安装 pg-py 额外包。在标准 UBUNTU (16 LTS) 中很简单,apt install postgresql-contrib postgresql-plpython.

CREATE FUNCTION get_csvfile(
  file text,
  delim_char char(1) = ',',
  quote_char char(1) = '"')
returns setof text[] stable language plpythonu as $$
  import csv
  return csv.reader(
     open(file, 'rb'),
     quotechar=quote_char,
     delimiter=delim_char,
     skipinitialspace=True,
     escapechar='\\'
  )
$$;

INSERT INTO mytable(info)
  SELECT jsonb_build_array(c[1],c[2],c[3]) 
  FROM get_csvfile('/tmp/myfile1.csv') c;
Run Code Online (Sandbox Code Playgroud)

split_csv()函数,这里定义。该csv.reader 是非常可靠的(!)。

未针对大型 CSV 进行测试...但预期 Python 可以完成工作。


PostgreSQL 解决方法

这不是一个完美的解决方案,但它解决了主要问题,即

...大的临时表,因此丢失了 CPU、磁盘和我的时间”...

这就是我们这样做的方式,一种解决方法file_fdw

  1. 采用您的约定以避免文件复制和文件权限混淆... CSV 的标准文件路径。例子:/tmp/pg_myPrj_file.csv

  2. 使用魔法扩展名初始化您的数据库或 SQL 脚本,

   CREATE EXTENSION file_fdw;
   CREATE SERVER files FOREIGN DATA WRAPPER file_fdw;
Run Code Online (Sandbox Code Playgroud)
  1. 对于每个 CSV 文件myNewData.csv

    3.1. scp为新文件创建符号链接(或远程复制)ln -sf $PWD/myNewData.csv /tmp/pg_socKer_file.csv

    3.2. 为您的新表配置file_fdw(假设mytable)。

   CREATE FOREIGN TABLE temp1 (a int, b text, c text) 
   SERVER files OPTIONS ( 
     filename '/tmp/pg_socKer_file.csv', 
       format 'csv', 
       header 'true'
   );
Run Code Online (Sandbox Code Playgroud)

PS:用 运行SQL 脚本后psql,当出现权限问题时,将链接的所有者改为sudo chown -h postgres:postgres /tmp/pg_socKer_file.csv

3.3. 使用file_fdw表作为源(假设正在填充mytable)。

 INSERT INTO mytable(info)
 SELECT json_build_array(a,b,c) FROM temp1;
Run Code Online (Sandbox Code Playgroud)

感谢@JosMac(和他的教程)!


注意:如果有 STDIN 方法(存在??),将很容易,避免权限问题和使用绝对路径。请参阅此答案/讨论