【问题标题】:Load TXT into postgres database, with non-present columns filled in as null将 TXT 加载到 postgres 数据库中,将不存在的列填充为 null
【发布时间】:2016-05-18 21:10:21
【问题描述】:

我是一个 python 新手,如果有一个我看不到的简单解决方案,请原谅我。我有大量 txt 文件 (~280) 需要读入 postgres 数据库中的表。该表的结构使其包含 txt 文件中存在的所有可能的列/变量。考虑下面的例子......

file1.txt

ID | Var_A | Var_B
1  | Apple | Dog
2  | Peach | Bird

file2.txt

ID | Var_A | Var_C
5  | Grape | Cat      
3  | Apple | Dog   

file3.txt:

ID | Var_B | Var_C
7  | Apple | Cat
6  | Peach | Bird

理想情况下,我希望我的表包含 txt 文件中的所有数据,以及 txt 文件中不存在的列/变量,记录为空白或 null。 (为了演示和清楚起见,我在下面将它们写为 null。)

postgres_table:

ID | Var_A | Var_B | Var_C
1  | Apple | Dog   | NULL
2  | Peach | Bird  | NULL
3  | Apple | NULL  | Dog
5  | Grape | NULL  | Cat
6  | NULL  | Peach | Bird
7  | NULL  | Apple | Cat

鉴于文件数量众多,这个过程需要自动化。我一直在 python 中使用 psycopg2 来完成这项任务,并且之前已经做了很多尝试,但都没有成功。我相信COPY 查询将是最有效的,(有数百万行数据,)但我在尝试复制时遇到了 txt 文件中不存在的列。

cursor = db.cursor()
query = "COPY postgres_table FROM '{}'(DELIMITER('|'));".format(~/file1.txt)
cursor.execute(query)
db.commit()

此查询产生以下错误:

psycopg2.DataError: missing data for column "Var_C"

也许有人能看到我看不到的东西。我也对该任务的其他潜在解决方案感兴趣。

【问题讨论】:

    标签: python database postgresql psycopg2


    【解决方案1】:

    一种选择是将文本文件作为字符串读取,然后修改字符串以有效地添加空值,然后将其传递给格式方法而不是文件。

    因此您可以读取文件的第一行,查看缺少哪些字段(将其与数据库表中的字段进行比较)并添加“|”在字符串的每一行中缺少字段的位置。

    【讨论】:

      【解决方案2】:

      您可以使用临时表将所有文件中的数据加载到其中,然后使用plpgsql 甚至plpython 执行您想要的操作。

      例如:

      -- Destination table
      create table if not exists dest(
        id int,
        var_a varchar,
        var_b varchar,
        var_c varchar);
      
      begin; -- Start transaction
      
      -- Temporary table to load data from all files
      create temporary table tt(
        tt_order serial,
        tt_id varchar,
        tt_var_1 varchar,
        tt_var_2 varchar,
        tt_file varchar)
      on commit drop; -- It will be drooped at the end of transaction
      
      -- Load data, header will be included
      copy tt(tt_id, tt_var_1, tt_var_2) from '~/file1.txt' (delimiter '|', header false);
      update tt set tt_file = '~/file1.txt' where tt_file is null;
      
      copy tt(tt_id, tt_var_1, tt_var_2) from '~/file2.txt' (delimiter '|', header false);
      update tt set tt_file = '~/file2.txt' where tt_file is null;
      
      copy tt(tt_id, tt_var_1, tt_var_2) from '~/file3.txt' (delimiter '|', header false);
      update tt set tt_file = '~/file3.txt' where tt_file is null;
      
      -- Remove spaces
      update tt set
        tt_id = trim(tt_id),
        tt_var_1 = trim(tt_var_1),
        tt_var_2 = trim(tt_var_2);
      
      select * from tt;
      
      -- Result is
      /*
       tt_order | tt_id | tt_var_1 | tt_var_2 |   tt_file   
      ----------+-------+----------+----------+-------------
              1 | ID    | Var_A    | Var_B    | ~/file1.txt
              2 | 1     | Apple    | Dog      | ~/file1.txt
              3 | 2     | Peach    | Bird     | ~/file1.txt
              4 | ID    | Var_A    | Var_C    | ~/file2.txt
              5 | 5     | Grape    | Cat      | ~/file2.txt
              6 | 3     | Apple    | Dog      | ~/file2.txt
              7 | ID    | Var_B    | Var_C    | ~/file3.txt
              8 | 7     | Apple    | Cat      | ~/file3.txt
              9 | 6     | Peach    | Bird     | ~/file3.txt
      (9 rows)
      */
      
      -- Move data to destination table
      do language plpgsql $$
      declare
        r record;
        q text;
      begin
        for r in select * from tt order by tt_order loop
          if lower(r.tt_id) = 'id' then -- If header from next file
            -- Build insert query
            q := 'insert into dest (id, ' || lower(r.tt_var_1) || ', ' || lower(r.tt_var_2) || ') values ($1::int, $2, $3)';
          else
            -- Insert data record
            execute q using r.tt_id, r.tt_var_1, r.tt_var_2;
          end if;
        end loop;
      end; $$;
      
      commit;
      
      select * from dest;
      
      -- Result is
      /*
       id | var_a | var_b | var_c 
      ----+-------+-------+-------
        1 | Apple | Dog   | 
        2 | Peach | Bird  | 
        5 | Grape |       | Cat
        3 | Apple |       | Dog
        7 |       | Apple | Cat
        6 |       | Peach | Bird
      (6 rows)
      */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-31
        • 2012-08-14
        • 1970-01-01
        • 1970-01-01
        • 2021-07-06
        • 1970-01-01
        • 1970-01-01
        • 2014-03-31
        相关资源
        最近更新 更多