Postgresql COPY 空字符串为 NULL 不起作用

Postgresql COPY empty string as NULL not work

我有一个包含一些整数列的 CSV 文件,现在它被保存为“”(空字符串)。

我想将它们复制到 table 作为 NULL 值。

使用 JAVA 代码,我尝试了这些:

String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',',  HEADER true)";
String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',', NULL ''  HEADER true)";

我得到:PSQLException:错误:数字类型的输入语法无效:“”

String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',', NULL '\"\"'  HEADER true)";

我得到:PSQLException:错误:CSV 引号字符不得出现在 NULL 规范中

有人做过吗?

我假设您知道数字数据类型没有“空字符串”('') 的概念。它是一个数字或 NULL(或 numeric 的 'NaN' - 但不是 integer 等人)

看起来您是从 text 这样的字符串数据类型导出的,并且其中有一些实际的空字符串 - 现在表示为 "" - " 是默认值 QUOTE CSV 格式的字符。

NULL 将由 nothing 表示,甚至没有引号。 The manual:

NULL

Specifies the string that represents a null value. The default is \N (backslash-N) in text format, and an unquoted empty string in CSV format.

不能 定义 "" 来通常表示 NULL 因为它已经表示一个空字符串。会有歧义。

要修复,我看到两个选项:

  1. 在提供给 COPY 之前编辑 CSV 文件/流,并将“”替换为 nothing。如果你在那里也有实际的空字符串可能会很棘手 - 或者 "" 在字符串中转义文字 "

  2. (我会做什么。)导入到具有相同结构的辅助临时 table,除了 integer 列转换为 text。然后 INSERT(或 UPSERT?)从那里到目标 table,即时正确转换 integer 值:

-- empty temp table with identical structure
CREATE TEMP TABLE tbl_tmp AS TABLE tbl LIMIT 0;

-- ... except for the int / text column
ALTER TABLE tbl_tmp ALTER col_int TYPE text;

COPY tbl_tmp ...;

INSERT INTO tbl  -- identical number and names of columns guaranteed
SELECT col1, col2, NULLIF(col_int, '')::int  -- list all columns in order here
FROM   tbl_tmp;

临时 table 会在会话结束时自动删除。如果您在同一个会话中多次 运行,要么只是 t运行 现有的临时文件 table,要么在每次交易后将其删除。

相关:

  • How to update selected rows with values from a CSV file in Postgres?
  • Rails Migrations: tried to change the type of column from string to integer
  • postgresql thread safety for temporary tables

从 Postgres 9.4 开始,您现在可以使用 FORCE_NULL。这会导致空字符串被转换为 NULL。非常方便,尤其是 CSV 文件(实际上只有在使用 CSV 格式时才允许这样做)。

语法如下:

COPY table FROM '/path/to/file.csv' 
WITH (FORMAT CSV, DELIMITER ';', FORCE_NULL (columnname));

文档中解释了更多详细信息:https://www.postgresql.org/docs/current/sql-copy.html