Postgresql

PostgreSQL ESCAPE 在製表符分隔的文件上引用:MySQL 有效,Pg 無效,我很困惑

  • July 11, 2022

我正在處理一些SEC 數據,這些數據在非正常則格式的製表符分隔文件中可用。

在 MySQL 上,我可以這樣導入這些文件:

CREATE TABLE import ( adsh text, tag text, version text, ddate text, qtrs text, uom text, dimh text, iprx text, value text, footnote text, footlen text, dimn text, coreg text, durp text, datp text, dcml text);

LOAD DATA INFILE '/pg/import/2011/Q2/num.tsv' INTO TABLE import FIELDS ESCAPED BY '' IGNORE 1 ROWS;

這適用於每個文件。但是,在 Pg 伺服器上執行的類似命令不起作用。在這種情況下,我使用該頁面上 .zip 中的 2011 年第二季度“num”數據。此文件是一個 40 列的製表符分隔文件。我在 Pg 伺服器上執行這個命令。

COPY import._2011_q2_num from '/pg/import/2011/Q2/num.tsv' DELIMITER E'\t' CSV HEADER;
ERROR:  unterminated CSV quoted field
CONTEXT:  COPY _2011_q2_num, line 830954: "0001193125-11-104388 DerivativeInstrumentsGainLossReclassifiedFromAccumulatedOCIIntoIncomeEffectiveP..."

根據 wc -l,該文件中有 830953 行。如果我刪除最後一行,錯誤仍然存在 - 它只是說它像 830953 一樣打開,等等。

我認為問題在於文件中出現了多個空欄位:

\t\t\t\t

(來自 od -c)。我認為 Pg 正在將那些連續的標籤視為轉義。文件說:

ESCAPE…預設值與 QUOTE 值相同(這樣如果引用字元出現在數據中,則加倍)。這必須是一個單字節字元。

好的,所以我必須為 ESCAPE 賦予一些價值,即使在這些文件中什麼都不會被轉義。文件中沒有 \b ,所以我嘗試了:

COPY import._2011_q2_num from '/pg/import/2011/Q2/num.tsv' DELIMITER E'\t' ESCAPE E'\b' CSV HEADER;

但是,我得到了同樣的錯誤。

\b 也許有些時髦?我還嘗試了波浪號(它出現在某些文件中,但我嘗試了一個沒有它的文件)和同樣的錯誤。

-- with E for ESCAPE byte
copy import._2011_q2_num from '/pg/import/2011/Q2/num.tsv' ESCAPE E'~' DELIMITER E'\t' CSV HEADER
-- without E
copy import._2011_q2_num from '/pg/import/2011/Q2/num.tsv' ESCAPE '~' DELIMITER E'\t' CSV HEADER

根據我的測試,大約四分之一的文件失敗,其餘的成功。每個文件中有數百萬行,因此手動檢查它們是不切實際的,而且我不認為這些文件的構造很糟糕,因為 MySQL 沒有問題。我想我只是沒有給出正確的 Pg 語法 - ?

這是 Debian 11.3 上的 PostgreSQL 13.5

根據錯誤消息,您的內容"在欄位中包含字元。

在 CSV 中,這是允許的,但僅限於用引號括起來的欄位("預設情況下),並且欄位內的引號被轉義(預設情況下帶有另一個引號)。如果未包含這些欄位,則會收到問題中提到的錯誤。

要藉助內容中不存在的字元來解決該問題,請使用QUOTE選項(不要使用ESCAPE)。通過設置QUOTE為 以外的其他內容""則將成為普通字元,這只是基本 TSV 文件所需要的。

引用自:https://dba.stackexchange.com/questions/314281