我有一个函数,即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)
我有几个问题:
我该怎么做才能解决这些问题?
答案 0 :(得分:0)
您希望导出不同数量的列的行。你正在制作一组数组,但是从那里想要生成一个CSV文件。
您的函数返回text[]
文字,即PostgreSQL数组文字。
这些是普遍认可的非CSV 。它们是逗号分隔的,是的,但它们遵循不同的语法规则。您无法将数组文字可靠地视为CSV行,反之亦然。
请勿尝试关闭分隔{...}
并将数组文字视为CSV行。
COPY
不适合你。它旨在处理关系,即统一的结构化行集,其中每列具有明确定义的类型,每行具有相同的列数。
您可以重新定义函数以返回setof record
并使用空值填充您的记录以始终保持相同的宽度,但它将非常丑陋且有限,加上CSV将包含空值。
COPY
将执行的操作是在单个CSV字段中导出包含数组文字的单个列CSV。这肯定不是你想要的。
您可能最好通过脚本或程序在客户端执行此操作以生成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])
或者,如果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