![](/img/trans.png)
[英]How can I put a psql meta-command in a psql variable to execute it later?
[英]How to ignore errors with psql \copy meta-command
我將psql
與 PostgreSQL 數據庫和以下copy
命令一起使用:
\COPY isa (np1, np2, sentence) FROM 'c:\Downloads\isa.txt' WITH DELIMITER '|'
我得到:
ERROR: extra data after last expected column
如何跳過有錯誤的行?
如果不跳過包括 Postgres 14 在內的整個命令,就無法跳過錯誤。目前沒有更復雜的錯誤處理。
\\copy
只是 SQL COPY
的包裝器,它通過 psql 傳遞結果。 COPY
手冊:
COPY
在出現第一個錯誤時停止操作。 這應該不會在COPY TO
的情況下導致問題,但是目標表已經在COPY FROM
收到了較早的行。 這些行將不可見或不可訪問,但它們仍會占用磁盤空間。 如果故障發生在大型復制操作中,這可能會浪費大量磁盤空間。 您可能希望調用VACUUM
來恢復浪費的空間。
大膽強調我的。 並且:
如果輸入文件的任何行包含的列比預期的多
COPY FROM
將引發錯誤。
COPY
是一種極其快速的數據導入/導出方式。 復雜的檢查和錯誤處理會減慢它的速度。
曾嘗試在 Postgres 9.0 中向COPY
添加錯誤日志記錄,但從未提交。
改為修復您的輸入文件。
如果您的輸入文件中有一個或多個附加列,並且該文件在其他方面是一致的,您可以向表isa
添加虛擬列,然后再刪除這些列。 或者(使用生產表進行清理)導入到臨時登台表並將選定的列(或表達式)從那里INSERT
到目標表isa
。
帶有詳細說明的相關答案:
太糟糕了,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'
這是一種解決方案——一次一行導入批處理文件。 性能可能會慢得多,但對於您的場景可能已經足夠了:
#!/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 和/或將其附加到文件中。
解決方法:使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.