在Postgres中传递CSV参数

时间:2009-08-28 02:59:18

标签: postgresql csv

我想将测试结果以.CSV文件的形式存储到中央数据库中。数据库的架构与CSV文件不匹配。理想情况下,我只是将CSV文件的内容作为字符串直接传递给服务器,并且具有可以将CSV转换为可以在INSERT中连接和使用的表的函数。

这是一个简化的例子:

INSERT INTO MyTable
SELECT *
FROM parse_csv(csv_data) t
INNER JOIN Categories c
ON t.CatID=c.CatID

注意:csv_data是包含CSV文件内容的varchar。另请注意直接在parse_csv的输出上完成的INNER JOIN操作。编写上面的parse_csv函数()的快速方法是什么?

我也在考虑使用OPENXML并传递XML字符串,但我在Postgres上找不到该功能。请参阅this question

我宁愿不在应用程序代码中解析CSV文件并调用INSERT一千次。这可能是很多不必要的往返。我知道COPY函数,但我有几个格式相同的CSV文件,我不想碰撞。

我愿意接受任何建议或提示。

1 个答案:

答案 0 :(得分:1)

只要您的CSV数据具有已知格式,就可以。

我们假设它们有两列:“CatID”和“WhatEver”。

现在你可以创建一个pl / perlu函数(或pl / pythonu,或者运气甚至pl / pgsql,但它会很棘手):

create type parse_csv_srf as (catid int4, whatever text);
create function parse_csv(text) returns setof parse_csv_srf as $$
...
$$ language plperlu;

函数的主体是在Perl(或Python,或其他)中进行解析,并返回(在Perl的情况下)对hashrefs数组的引用,其中每个散列应该具有键“catid”和“whatever”与一些价值观。

以下示例只是一个示例 - 使用regexp编写csv解析器是个坏主意,你永远不应该这样做,但我太懒了,无法提供实际工作的解析器作为示例的一部分。

CREATE type parse_csv_srf as (catid INT4, whatever TEXT);
CREATE OR REPLACE FUNCTION parse_csv( TEXT ) RETURNS setof parse_csv_srf as $$
my $source = shift;
my @rows = split /\r?\n/, $source;
my @reply = ();
for my $row (@rows) {
    my @values = ();
    while ( $row =~ s/("(?:[^"]|"")*"|[^",]*)(,|$)// ) {
        my $single_value = $1;
        $single_value =~ s/^"//;
        $single_value =~ s/"$//;
        $single_value =~ s/""/"/g;
        push @values, $single_value;
        last if '' eq $row;
    }
    push @reply, {
        "catid" => $values[0],
        "whatever" => $values[1],
    };
}
return \@reply;
$$ language plperl;

# select * from parse_csv(E'1,depesz\n2,"hubert lubaczewski"\n');
 catid |      whatever
-------+--------------------
     1 | depesz
     2 | hubert lubaczewski
(2 rows)

# select i.*, c.relpages
  from parse_csv(E'1,pg_database\n2,"pg_proc"\n') as i
       join pg_class c on i.whatever = c.relname;
 catid |  whatever   | relpages
-------+-------------+----------
     1 | pg_database |        1
     2 | pg_proc     |       53
(2 rows)