在 csv 文件中导入 postgres json 数据

mar*_*osh 9 postgresql import json csv

我正在尝试将csv包含表数据的文件导入 postgres 。表的列之一具有jsonb类型。

我的csv文件的一行包含类似

1,{"a":"b"}
Run Code Online (Sandbox Code Playgroud)

假设表有一个模式

id              | smallint          | 
data            | jsonb             | 
Run Code Online (Sandbox Code Playgroud)

如果我只是尝试插入数据,一切正常

INSERT INTO table VALUES (1, '{"a":"b"}');
Run Code Online (Sandbox Code Playgroud)

尝试直接从文件导入

COPY table FROM '/path/to/file.csv' DELIMITER ',' csv;
Run Code Online (Sandbox Code Playgroud)

给了我以下错误:

ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY availability, line 1, column services: "{a: b}"
Run Code Online (Sandbox Code Playgroud)

我试图用', with ", with\"\',但没有任何效果。

哪个是正确的语法呢?

Eva*_*oll 7

PostgreSQLCOPY命令很少是理想的,但它通常有效。作为参考,有比猜测更好的方法来解决这个问题。

CREATE TEMP TABLE baz AS
  SELECT 1::int, '{"a":"b"}'::jsonb;
Run Code Online (Sandbox Code Playgroud)

这是您的确切示例数据。现在我们可以测试不同的设置..

# COPY baz TO STDOUT;
1   {"a": "b"}

COPY baz TO STDOUT DELIMITER ',';
1,{"a": "b"}
Run Code Online (Sandbox Code Playgroud)

你会看到上面生成了你提问的确切数据......

COPY baz TO '/tmp/data.csv' DELIMITER ',';
Run Code Online (Sandbox Code Playgroud)

没有问题。至少不是 PostgreSQL 9.5。

CSV 模式

那么你的问题在哪里,它是 CSV 模式。观察,

# COPY baz TO STDOUT;
1   {"a": "b"}
# COPY baz TO STDOUT CSV;
1,"{""a"": ""b""}"
Run Code Online (Sandbox Code Playgroud)

你现在可以看到这两者是不同的。让我们尝试以 CSV 模式加载非 CSV 文件,该模式采用上述 CSV 模式生成的格式。

TRUNCATE baz;
COPY baz FROM '/tmp/data.csv' DELIMITER ',' CSV;
ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: {a...
COPY baz, line 1, column jsonb: "{a: b}"
Run Code Online (Sandbox Code Playgroud)

现在我们出错了。原因来自RFC 4180

每个字段可能会也可能不会被双引号括起来(但是某些程序,例如 Microsoft Excel,根本不使用双引号)。 如果字段未用双引号括起来,则字段内可能不会出现双引号。

  1. 因此JSON RFC 4627指定名称/值对中的对象名称必须是需要双引号的字符串。
  2. CSV RFC 4180个指定如果任何双引号里面的字段,然后整场必须加引号。

此时你有两个选择..

  1. 不要使用 CSV 模式。
  2. 或者,转义内部引号。

因此,这些将是 CSV 模式下相同选项下的有效输入。

#COPY baz TO STDOUT DELIMITER ',' CSV ESCAPE E'\\';
1,"{\"a\": \"b\"}"

# COPY baz TO STDOUT DELIMITER ',' CSV;
1,"{""a"": ""b""}"
Run Code Online (Sandbox Code Playgroud)


mar*_*osh 3

找到了解决方案,postgres使用"作为转义字符,所以正确的格式应该是

{"""a""": """b"""}
Run Code Online (Sandbox Code Playgroud)