2009-08-28 47 views
0

我想將測試結果以.CSV文件的形式存儲到中央數據庫中。數據庫具有與CSV文件不匹配的架構。理想情況下,我只是將CSV文件的內容作爲字符串直接傳遞給服務器,並且具有可以將CSV轉換爲可以在INSERT中進行連接和使用的表的功能。在Postgres中傳遞CSV參數

這裏有一個簡單的例子:

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

只要您的CSV數據具有已知格式,就有可能。

我們假設他們有2列:「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數組的引用,其中每個hash應該具有帶有一些值的鍵「catid」和「whatever」。

下面的例子只是一個例子 - 用正則表達式寫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)