我正在使用psql
和PostgreSQL数据库以及以下copy
命令:
\COPY isa (np1, np2, sentence) FROM 'c:\Downloads\isa.txt' WITH DELIMITER '|'
我明白了:
ERROR: extra data after last expected column
如何跳过有错误的行?
答案 0 :(得分:12)
如果不跳过包括Postgres 9.5在内的整个命令,则不能跳过错误。目前没有更复杂的错误处理。
\copy
只是SQL COPY
的包装器,它通过psql传递结果。 COPY
的手册:
COPY
在第一次错误时停止操作。这不应该导致 在COPY TO
的情况下出现问题,但目标表已经存在 已收到COPY FROM
中的早期行。这些行不会 可见或可访问,但它们仍然占用磁盘空间。这有可能 如果失败,则相当于浪费了相当多的磁盘空间 发生在大型复制操作中。你可能希望调用VACUUM
恢复浪费的空间。
大胆强调我的。和
如果输入文件的任何行包含,
COPY FROM
将引发错误 列数多于或少于预期。
有一个attempt to add error logging to COPY
in Postgres 9.0,由Aster Data带头,但它从未被提交过。该公司后来被Teradata收购,所以我怀疑他们仍然在追求这个项目。
修改输入文件。
如果输入文件中有一个或多个附加列,并且文件另外一致,则可以向表isa
添加虚拟列,然后删除它们。或者(带有生产表的清洁工)从那里导入临时临时表和INSERT
个选定列(或表达式)到目标表isa
。
相关答案及详细说明:
答案 1 :(得分:4)
太糟糕了,25 年来 Postgres 没有 -ignore-errors
标志或 COPY
命令选项。在这个大数据时代,您会得到很多脏记录,而且项目修复每个异常值的成本可能非常高。
我不得不以这种方式解决:
dummy_original_table
CREATE OR REPLACE FUNCTION on_insert_in_original_table() RETURNS trigger AS $$
DECLARE
v_rec RECORD;
BEGIN
-- we use the trigger to prevent 'duplicate index' error by returning NULL on duplicates
SELECT * FROM original_table WHERE primary_key=NEW.primary_key INTO v_rec;
IF v_rec IS NOT NULL THEN
RETURN NULL;
END IF;
BEGIN
INSERT INTO original_table(datum,primary_key) VALUES(NEW.datum,NEW.primary_key)
ON CONFLICT DO NOTHING;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
RETURN NULL;
END;
psql dbname -c \copy dummy_original_table(datum,primary_key) FROM '/home/user/data.csv' delimiter E'\t'
答案 2 :(得分:1)
这是一种解决方案——一次一行导入批处理文件。性能可能会慢得多,但对于您的场景来说可能已经足够了:
#!/bin/bash
input_file=./my_input.csv
tmp_file=/tmp/one-line.csv
cat $input_file | while read input_line; do
echo "$input_line" > $tmp_file
psql my_database \
-c "\
COPY my_table \
FROM `$tmp_file` \
DELIMITER '|'\
CSV;\
"
done
此外,您可以修改脚本以捕获 psql
stdout/stderr 并退出
状态,如果退出状态不为零,则将 $input_line
和捕获的 stdout/stderr 回显到 stdin 和/或将其附加到文件中。
答案 3 :(得分:0)
解决方法:使用 sed
删除报告的错误行并再次运行 \copy
更高版本的 Postgres(包括 Postgres 13),将报告错误的行号。然后,您可以使用 sed
删除该行并再次运行 \copy,例如,
#!/bin/bash
bad_line_number=5 # assuming line 5 is the bad line
sed ${bad_line_number}d < input.csv > filtered.csv