在PostgreSQL中创建包含许多列的表

在PostgreSQL中创建包含许多列的表,postgresql,Postgresql,为了在我的例子中使用COPY,我需要首先从PostgreSQL中的csv文件函数创建目标表 例如,如果我的表有60列,手动编写以下内容会让人感到奇怪和低效: CREATE TABLE table_name( column1 datatype, column2 datatype, column3 datatype, ..... column60 datatype 那些使用PostgreSQL的人-如何解决这个问题?我通常使用文件扩展名从CSV文件读取数据 但不幸的是

为了在我的例子中使用COPY,我需要首先从PostgreSQL中的csv文件函数创建目标表

例如,如果我的表有60列,手动编写以下内容会让人感到奇怪和低效:

CREATE TABLE table_name(
   column1 datatype,
   column2 datatype,
   column3 datatype,
   .....
   column60 datatype
那些使用PostgreSQL的人-如何解决这个问题?

我通常使用文件扩展名从CSV文件读取数据

但不幸的是,当您解决诸如从包含多个列的CSV文件读取之类的任务时,file_fdw并不是那么方便/灵活。CREATETABLE可以处理任意数量的列,但如果它与CSV文件不对应,则稍后在执行SELECT时将失败。所以表的显式创建问题仍然存在。然而,解决这个问题是可能的

这是一种暴力方法,除了博士后,它不需要任何东西。该函数用PL/pgSQL编写,尝试创建一个只有一列的表,并尝试从中进行选择。如果失败,它将删除该表并重试,但有2列。依此类推,直到选择确定为止。所有列都是文本类型–这是一个很大的限制,但它仍然解决了准备好选择表而不是手动操作的任务

create or replace function autocreate_table_to_read_csv(
  fdw_server text,
  csv text,
  table_name text,
  max_columns_num int default 100
) returns void as $$
declare
  i int;
  sql text;
  rec record;
begin
  execute format('drop foreign table if exists %I', table_name);
  for i in 1..max_columns_num loop
    begin
      select into sql
       format('create foreign table %I (', table_name)
          || string_agg('col' || n::text || ' text', ', ')
          || format(
            e') server %I options ( filename \'%s\', format \'csv\' );',
            fdw_server,
            csv
          )
      from generate_series(1, i) as g(n);
      raise debug 'SQL: %', sql;
      execute sql;
      execute format('select * from %I limit 1;', table_name) into rec;
      -- looks OK, so the number of columns corresponds to the first row of CSV file
      raise info 'Table % created with % column(s). SQL: %', table_name, i, sql;
      exit;
    exception when others then
      raise debug 'CSV has more than % column(s), making another attempt...', i;
    end;
  end loop;
end;
$$ language plpgsql;
一旦找到适当数量的列,它将报告有关它的信息,请参见raise info

要查看更多详细信息,请运行set client_min_messages To debug;在使用该函数之前

使用示例:

test=# create server csv_import foreign data wrapper file_fdw;
CREATE SERVER

test=# set client_min_messages to debug;
SET

test=# select autocreate_table_to_read_csv('csv_import', '/home/nikolay/tmp/sample.csv', 'readcsv');
NOTICE:  foreign table "readcsv" does not exist, skipping
DEBUG:  SQL: create foreign table readcsv (col1 text) server csv_import options ( filename '/home/nikolay/tmp/sample.csv', format 'csv' );
DEBUG:  CSV has more than 1 column(s), making another attempt...
DEBUG:  SQL: create foreign table readcsv (col1 text, col2 text) server csv_import options ( filename '/home/nikolay/tmp/sample.csv', format 'csv' );
DEBUG:  CSV has more than 2 column(s), making another attempt...
DEBUG:  SQL: create foreign table readcsv (col1 text, col2 text, col3 text) server csv_import options ( filename '/home/nikolay/tmp/sample.csv', format 'csv' );
INFO:  Table readcsv created with 3 column(s). SQL: create foreign table readcsv (col1 text, col2 text, col3 text) server csv_import options ( filename '/home/nikolay/tmp/sample.csv', format 'csv' );
 autocreate_table_to_read_csv
------------------------------

(1 row)

test=# select * from readcsv limit 2;
 col1  | col2  | col3
-------+-------+-------
 1313  | xvcv  | 22
 fvbvb | 2434  | 4344
(2 rows)
更新:发现了非常类似的实现,但没有暴力,需要在CSV文件方法中明确指定列,以便复制。。发件人:


另外,事实上,这将是一个非常好的任务,以改善文件的fdw和复制。。由于Postgres的功能使其更加灵活——例如,对于Postgres_fdw,有一个非常方便的导入外来模式命令,它允许非常快速地定义远程外来对象,只需一行——它节省了大量工作。在CSV DTA中有类似的东西是很棒的。

你可以使用ORM/驱动程序在你的语言选择中动态地做到这一点,虽然我会认真考虑如果你真的需要一个表中的60列,即使它们只有30,我也要频繁地打开各种CSV文件并进行各种数据操作。每次我想在csv文件上使用sql时,手动创建一个表对我来说没有什么意义。在这种情况下,实现自动化的最佳选择是用您喜欢的语言编写脚本。我会在Node+Knex中完成。