Передайте параметр CSV в Postgres - PullRequest
0 голосов
/ 28 августа 2009

Я хочу сохранить результаты теста в виде файла .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 - это varchar с содержимым файла CSV. Также обратите внимание, что операция INNER JOIN выполняется непосредственно на выходе parse_csv. Какой быстрый способ написать выше функцию parse_csv ()?

Я также думаю об использовании OPENXML и передаче строки XML, но я не могу найти эту функцию в Postgres. См этот вопрос .

Я бы предпочел не анализировать файл CSV в коде приложения и вызывать INSERT тысячу раз. Это может быть много ненужных поездок туда и обратно. Я знаю функцию COPY, но у меня есть несколько CSV-файлов одного формата, с которыми я не хочу сталкиваться.

Я открыт для любых предложений или советов.

1 Ответ

1 голос
/ 28 августа 2009

Это возможно, если данные 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) ссылку на массив хеш-ссылок, где каждый хеш должен иметь ключи «catid» и «что угодно» с некоторые значения.

Следующий пример является лишь примером - написание парсера 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...