【问题标题】:Invalid input syntax for type uuid: "" or "null" in PosgreSQL copy commanduuid 类型的输入语法无效:PostgreSQL 复制命令中的“”或“null”
【发布时间】:2021-04-08 14:23:49
【问题描述】:

我已经从 SELECT 查询中创建了 csv-backup,现在尝试将其导入回数据库。但是我收到了这个错误:

COPY doc FROM '/tmp/doc.csv' DELIMITER ',' CSV HEADER;


ERROR: invalid input syntax for type uuid: "null"

如您所见,我的文件中有 NULL 为 "null"

这发生在之前为空的可选字段上。

我找到了这个解决方案:https://stackoverflow.com/a/40428667/8443131

但这对我不起作用:

COPY doc FROM '/tmp/doc.csv' DELIMITER ',' CSV HEADER QUOTE '"null"' NULL '';

ERROR:  COPY quote must be a single one-byte character

如何导入此文件?

UPD:我尝试用空引号替换空值。

命令尝试:

COPY doc FROM '/tmp/null.csv' DELIMITER ',' CSV HEADER QUOTE '"' NULL '';

ERROR:  invalid input syntax for type uuid: ""

短版文件:

"id","removed","modified_at","root_id","parent_id","acl","properties","data","file_meta"
"f6a16ff7-4a31-11eb-be7b-8344edc8f36b","false","2021-01-04 00:00:12.347988","","","IS_PUBLIC","","",""
"2fdd0b8b-4a70-11eb-99fd-ad786a821574","false","2021-01-04 00:00:06.87298","","","IS_PUBLIC","","",""
"2c6d5fd1-4a70-11eb-99fd-ad786a821574","false","2021-01-04 00:00:07.536212","","","IS_PUBLIC","","",""
"fd645c21-4a6f-11eb-99fd-ad786a821574","false","2021-01-04 00:00:11.892367","","","IS_PUBLIC","","",""
"35c1fc53-4a70-11eb-99fd-ad786a821574","false","2021-01-04 00:00:05.517109","","","IS_PUBLIC","","",""
"35d165a4-4a70-11eb-99fd-ad786a821574","false","2021-01-04 00:00:01.72546","","","IS_PUBLIC","","",""
"fd40806d-4a6f-11eb-99fd-ad786a821574","false","2021-01-04 00:00:09.173726","","","IS_PUBLIC","","",""
"30ba4b45-4a70-11eb-99fd-ad786a821574","false","2021-01-04 00:00:04.655073","","","IS_PUBLIC","","",""

表创建:


-- Dumped from database version 13.0 (Debian 13.0-1.pgdg100+1)
-- Dumped by pg_dump version 13.0 (Debian 13.0-1.pgdg100+1)



CREATE TABLE public.doc (
    id uuid NOT NULL,
    removed boolean,
    modified_at timestamp without time zone,
    root_id uuid,
    parent_id uuid,
    acl jsonb,
    properties jsonb,
    data jsonb,
    file_meta jsonb
);



ALTER TABLE ONLY public.doc
    ADD CONSTRAINT doc_pkey PRIMARY KEY (id);

ALTER TABLE ONLY public.doc
    ADD CONSTRAINT fk_document_entity FOREIGN KEY (id) REFERENCES public.main_table(id);

ALTER TABLE ONLY public.doc
    ADD CONSTRAINT fk_document_parent FOREIGN KEY (parent_id) REFERENCES public.doc(id);

【问题讨论】:

  • @a_horse_with_no_name 谢谢,现在我明白了。但我的 null 定义中有引号字符,但它失败了:COPY doc FROM '/tmp/doc.csv' DELIMITER ',' CSV HEADER NULL '"null"' QUOTE '"'。如果我从"null" 中删除引号,它会像以前一样失败。我的其他数据(例如 uuids)也在引号 "" 中。
  • 我试过CSV HEADER NULL 'null' QUOTE '"',但它又说invalid input syntax for type uuid: "null"
  • COPY doc FROM program 'sed -e ''s/""//g'' /tmp/null.csv' WITH (DELIMITER ',', FORMAT CSV, HEADER, QUOTE '"', NULL '');
  • @Abelisto 移动了一些东西。现在 jsonb 出错了:ERROR: invalid input syntax for type json DETAIL: Token "IS_PUBLIC" is invalid. CONTEXT: JSON data, line 1: IS_PUBLIC COPY document_meta, line 2, column acl: "IS_PUBLIC"。但我想我可以用{} 或其他东西来逃避它
  • 请注意,前面的sed 命令替换了所有出现的""。实际的命令应该是 sed -e 's/^""//g' -e 's/,""$/,/g' -e 's/,"",/,,/g'

标签: postgresql csv database-backups


【解决方案1】:

假设第二列是boolean,第三列是timestamp,我用以下内容复制了您的案例

create table test (col1 varchar, col2 boolean, col3 timestamp, col4 varchar, col5 varchar, col6 varchar, col7 varchar, col8 varchar, col9 varchar)                                  ;                                                                                               

如果我现在使用

copy test from STDIN delimiter ',' CSV QUOTE '"' NULL 'null';

并传递你提到的字符串

"f6a16ff7-4a31-11eb-be7b-8344edc8f36b","false","2021-01-04 00:00:12.347988","null","null","IS_PUBLIC","null","null","null"

数据解析正确

COPY 1

表格的输出看起来是正确的。

defaultdb=> select * from test;
                 col1                 | col2 |            col3            | col4 | col5 |   col6    | col7 | col8 | col9 
--------------------------------------+------+----------------------------+------+------+-----------+------+------+------
 f6a16ff7-4a31-11eb-be7b-8344edc8f36b | f    | 2021-01-04 00:00:12.347988 | null | null | IS_PUBLIC | null | null | null
(1 row)

【讨论】:

  • 这基本上是来自链接的查询。我试过了,但没有任何改变。我从文件中添加了表查询和示例行。我还尝试将空值更改为“”,因为它在链接问题中。
【解决方案2】:

您无法使用COPY 加载此文件,因为"null" 用双引号引起来,因此不能用作NULL 占位符——它总是被解释为字符串。

您可以做的最好的事情是将文件加载到一个表中,其中各个列定义为text,然后执行类似的操作

ALTER TABLE doc ALTER uuidcol TYPE uuid USING CAST(nullif(uuidcol, 'null') AS uuid);

【讨论】:

  • 我也尝试将其更改为链接问题中的“”或“^”,但仍然没有运气
  • 那条评论是什么意思?我的回答有问题吗?
  • 我想说我试图更改这个文件来上传它。由于当前表中有数据,我无法创建另一个表。
  • 如果你去掉双引号,它将与NULL 'null'一起使用。
【解决方案3】:

即使@Abelisto 命令有效,我仍然无法上传一些 jsonb 行。

但我也有一个 .json 替代文件,如下所示:

[
    {
        "c0": "f6a16ff7-4a31-11eb-be7b-8344edc8f36b",
        "c1": false,
        "c2": "2021-01-04 00:00:12.347988",
        "c3": null,
        "c4": null,
        "c5": "IS_PUBLIC",
        "c6": null,
        "c7": null,
        "c8": null
    },
    ...
]

所以我最终编写了这个对我有用的 python 脚本:

import json
import psycopg2
from datetime import datetime
import uuid


connection = psycopg2.connect(user="admin",
                              password="admin",
                              host="127.0.0.1",
                              port="5432",
                              database="postgres")
cursor = connection.cursor()


def insertLine(line):

    id = uuid.UUID(line['c0']).hex

    removed = bool(line['c1'])

    modified_at = datetime.strptime(line['c2'], '%Y-%m-%d %H:%M:%S.%f')

    root_id = uuid.UUID(line['c3']).hex if line['c3'] else None
    parent_id = uuid.UUID(line['c4']).hex if line['c4'] else None

    acl = json.dumps(line['c5']) if line['c5'] else None

    properties = json.dumps(line['c6']) if line['c6'] else None
    data = json.dumps(line['c7']) if line['c7'] else None
    file_meta = json.dumps(line['c8']) if line['c8'] else None

    record_to_insert = (id, removed, modified_at, root_id,
                        parent_id, acl, properties, data, file_meta)

    try:
        postgres_insert_query = """INSERT INTO doc (id, removed, modified_at, root_id, parent_id, acl, properties, data, file_meta) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
        
        cursor.execute(postgres_insert_query, record_to_insert)

        connection.commit()
        count = cursor.rowcount


    except psycopg2.Error as error:
        print("ERROR:" + str(error))


file = 'table.json'

with open(file) as json_file:
    data = json.load(json_file)
    for p in data:
        insertLine(p)


if connection:
    cursor.close()
    connection.close()
    print("PostgreSQL connection is closed")

所以我想在 csv 中备份 jsonb 字段只是一种不好的做法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 2023-01-15
    • 1970-01-01
    • 2018-09-29
    • 2020-02-29
    • 1970-01-01
    • 2019-03-09
    相关资源
    最近更新 更多