簡體   English   中英

如何使用 psql \\copy 元命令忽略錯誤

[英]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命令選項。 在這個大數據時代,你會得到很多臟記錄,項目修復每個異常值的成本可能非常高。

我不得不以這種方式解決問題:

  1. 復制原表並命名為dummy_original_table
  2. 在原始表中,創建一個這樣的觸發器:
    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;
  1. 將副本運行到虛擬表中。 那里不會插入任何記錄,但都會插入到 original_table 中

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

[根據@Botond_Balázs 的評論]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM