我想将测试结果以.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文件,我不想碰撞。
我愿意接受任何建议或提示。
答案 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)