将数组导出到PL / pgSQL中的CSV文件中

时间:2015-09-16 11:27:58

标签: arrays postgresql csv plpgsql postgresql-copy

我有一个函数,即RETURNS SETOF text []。此功能的示例结果:

{080213806381,"personal data1","question 1",answer1,"question 2",answer2,"question 3","answer 3"}
{080213806382,"personal data1","question 1",answer1,"question 2",answer2,"question 3","answer 3"}

我用以下语句形成每一行:

resultRow := array_append(resultRow, fetchedRow.data::text);

然后:

RETURN NEXT resultRow;

这是我的COPY命令:

COPY( 
SELECT myFunction()
) TO 'D:\test_output.csv' WITH (FORMAT 'csv', DELIMITER E',', HEADER false)

我有几个问题:

  1. 无论值是以相同的方式附加到数组的事实,其中一些是双引号而其中一些不是。这在某种程度上取决于值中是否存在空格字符。例如,看看数组的第一个元素或者答案2和"回答3"在每一行。我想要一些统一的行为。
  2. 使用COPY命令导出到CSV后,我在开头和结尾处获得所有这些花括号的相同行。我不想用CSV格式。
  3. 我该怎么做才能解决这些问题?

2 个答案:

答案 0 :(得分:0)

您希望导出不同数量的列的行。你正在制作一组数组,但是从那里想要生成一个CSV文件。

即时问题 - 数组文字不是CSV

您的函数返回text[]文字,即PostgreSQL数组文字。

这些是普遍认可的非CSV 。它们是逗号分隔的,是的,但它们遵循不同的语法规则。您无法将数组文字可靠地视为CSV行,反之亦然。

请勿尝试关闭分隔{...}并将数组文字视为CSV行。

COPY无法正常运行

COPY不适合你。它旨在处理关系,即统一的结构化行集,其中每列具有明确定义的类型,每行具有相同的列数。

您可以重新定义函数以返回setof record并使用空值填充您的记录以始终保持相同的宽度,但它将非常丑陋且有限,加上CSV将包含空值。

COPY将执行的操作是在单个CSV字段中导出包含数组文字的单个列CSV。这肯定不是你想要的。

解决方案1:导出客户端

您可能最好通过脚本或程序在客户端执行此操作以生成CSV。让程序接收数组,然后通过合适的库(如Python的csv模块)将其写入CSV。选择一种客户端脚本语言,其中PostgreSQL驱动程序可以理解数组,并可以使用语言格式将它们转换为数组 - 再次,如Python的psycopg2

e.g。给出虚函数:

CREATE OR REPLACE FUNCTION get_rows() RETURNS setof text[] AS $$
VALUES
('{080213806381,"personal data1","question 1",answer1,"question 2",answer2,"question 3","answer 3"}'::text[]),
('{080213806382,"personal data1","question 1",answer1,"question 2",answer2,"question 3","answer 3","q4","a4"}'::text[])
$$ LANGUAGE SQL;

客户端脚本可以简单如下:

#!/usr/bin/env python
import psycopg2
import csv

with psycopg2.connect('dbname=craig') as conn:
    curs = conn.cursor()

    with open("test.csv","w") as csvfile:
        f = csv.writer(csvfile)

        curs.execute("SELECT * FROM get_rows()")

        for row in curs:
            f.writerow(row[0])

解决方案2:直接从过程

导出CSV

或者,如果CSV文档不是太大,您可以在单个过程中生成整个CSV,可能使用plpythonu和csv模块,或类似的CSV库作为首选过程语言。由于整个CSV文档必须在内存中累积,因此无法扩展到非常大的文档。

答案 1 :(得分:0)

使用文本数组作为结果格式是错误的想法 - 文本数组格式不能简单地用CSV格式转换。改为返回表

CREATE OR REPLACE FUNCTION foo()
RETURNS TABLE(c1 text, c2 text, c3 text, c4 text, c5 text, c6 text, c7 text, c8 text)
AS $$
  VALUES('080213806381','personal data1','question 1','answer1','question 2','answer2','question 3','answer 3'),
        ('080213806382','personal data1','question 1','answer1','question 2','answer2','question 3','answer 3');
$$ LANGUAGE sql;

postgres=# COPY (SELECT * FROM foo()) TO stdout CSV;
080213806381,personal data1,question 1,answer1,question 2,answer2,question 3,answer 3
080213806382,personal data1,question 1,answer1,question 2,answer2,question 3,answer 3
Time: 1.228 ms