【问题标题】:How to ignore some rows while importing from a tab separated text file in PostgreSQL?从 PostgreSQL 中的制表符分隔的文本文件导入时如何忽略某些行?
【发布时间】:2016-12-29 06:42:41
【问题描述】:

我有一个 30 GB 的制表符分隔文本文件,其中包含超过 1 亿行,当我想使用 \copy 命令将此文本文件导入 PostgreSQL 表时,某些行会导致错误。如何在导入到 postgresql 时忽略这些行并记录被忽略的行?

我通过 SSH 连接到我的机器,所以我无法使用 pgadmin!

在导入之前编辑文本文件非常困难,因为很多不同的行都有不同的问题。如果有一种方法可以在导入之前逐一检查行,然后对各个行运行 \copy 命令,那将很有帮助。

下面是生成表格的代码:

CREATE TABLE Papers(
    Paper_ID CHARACTER(8) PRIMARY KEY,
    Original_paper_title TEXT,
    Normalized_paper_title TEXT,
    Paper_publish_year INTEGER, 
    Paper_publish_date DATE,
    Paper_Document_Object_Identifier TEXT,
    Original_venue_name TEXT,
    Normalized_venue_name TEXT,
    Journal_ID_mapped_to_venue_name CHARACTER(8),
    Conference_ID_mapped_to_venue_name CHARACTER(8),
    Paper_rank BIGINT,
    FOREIGN KEY(Journal_ID_mapped_to_venue_name) REFERENCES Journals(Journal_ID),
    FOREIGN KEY(Conference_ID_mapped_to_venue_name) REFERENCES Conferences(Conference_ID));

【问题讨论】:

  • 好的。标志已收回。
  • @dmfay 在导入之前很难编辑文本文件,因为很多不同的行都有不同的问题。如果有一种方法可以在导入之前逐一检查行,然后对各个行运行 \copy 命令,那将很有帮助。

标签: sql postgresql text


【解决方案1】:

不要直接加载到目标表,而是加载到单列临时表。

create table Papers_stg (rec text);

加载完所有数据后,您可以使用 SQL 对数据进行验证。

查找字段数错误的记录:

select  rec
from    Papers_stg
where   cardinality(string_to_array(rec,'       ')) <> 11

创建一个包含所有文本字段的表格

create table Papers_fields_text
as
select  fields[1]  as Paper_ID                          
       ,fields[2]  as Original_paper_title              
       ,fields[3]  as Normalized_paper_title            
       ,fields[4]  as Paper_publish_year                
       ,fields[5]  as Paper_publish_date                
       ,fields[6]  as Paper_Document_Object_Identifier  
       ,fields[7]  as Original_venue_name               
       ,fields[8]  as Normalized_venue_name             
       ,fields[9]  as Journal_ID_mapped_to_venue_name   
       ,fields[10] as Conference_ID_mapped_to_venue_name
       ,fields[11] as Paper_rank                        

from   (select  string_to_array(rec,'       ')  as fields
        from    Papers_stg
        ) t
where   cardinality(fields) = 11

对于字段转换检查,您可能需要使用here 中描述的概念

【讨论】:

  • 如何将数据从我的 11 列制表符分隔的文本文件导入到单个列表中?
  • 使用文本文件中不存在的字符作为分隔符
  • 这是一个 30 GB 的文本文件,包含多种语言。任何字符都可以存在。从 11 列文件导入到 1 列表没有更准确的方法吗?
  • 可以'\n'作为分隔符吗?
  • 您不能使用 '\n' 但可以使用控制字符,例如 SUBSTITUTE (hex = 1A),例如\copy t from c:\Temp\t.txt with delimiter E'\x1A'
【解决方案2】:

您唯一的选择是使用逐行处理。编写shell脚本(例如),它将循环输入文件并将每一行发送到“复制”,然后检查执行结果,然后将失败的行写入一些“err_input.txt”。

更复杂的逻辑可以提高处理速度。使用“部分”而不是逐行并在失败的段上使用逐行逻辑。

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      您可以使用BEFORE INSERT - 触发器并检查您的条件。如果记录未通过检查,则写入日志(或将条目写入单独的表)并返回null。如果可能的话,您甚至可以更正一些值。

      当然,如果检查条件需要其他查询(例如查找重复键等),您可能会遇到性能问题。但我不确定你的意思是哪种“不同行中的不同问题”......

      StackExchange Database Administrators上也给出答案,下面的例子取自Bartosz Dmytrak at PostgreSQL forum

      CREATE OR REPLACE FUNCTION "myschema"."checkTriggerFunction" ()
      RETURNS TRIGGER
      AS
      $BODY$
      BEGIN
      IF EXISTS (SELECT 1 FROM "myschema".mytable WHERE "MyKey" = NEW."MyKey")
      THEN
       RETURN NULL;
      ELSE
       RETURN NEW;
      END IF;
      END;
      $BODY$
      LANGUAGE plpgsql;
      
      and trigger:
      CREATE TRIGGER "checkTrigger"
        BEFORE INSERT
        ON "myschema".mytable
        FOR EACH ROW
        EXECUTE PROCEDURE "myschema"."checkTriggerFunction"();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-17
        • 2017-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-06
        • 2021-10-25
        • 1970-01-01
        相关资源
        最近更新 更多