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
因为它已经表示一个空字符串。会有歧义。
要修复,我看到两个选项:
在提供给 COPY
之前编辑 CSV 文件/流,并将“”替换为 nothing。如果你在那里也有实际的空字符串可能会很棘手 - 或者 ""
在字符串中转义文字 "
。
(我会做什么。)导入到具有相同结构的辅助临时 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
我有一个包含一些整数列的 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
因为它已经表示一个空字符串。会有歧义。
要修复,我看到两个选项:
在提供给
COPY
之前编辑 CSV 文件/流,并将“”替换为 nothing。如果你在那里也有实际的空字符串可能会很棘手 - 或者""
在字符串中转义文字"
。(我会做什么。)导入到具有相同结构的辅助临时 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