2016-08-18 4 views
1

私は、テキスト配列(text[])型の列を持つテーブルを持っています。 COPYコマンドを使用してCSVをコピーしたいのですが、私はPsycopg2のコピー機能を使用していますが、この質問は一般的にPostgresに関連しています。PostgresはCOPYでARRAY構文を使用できません

Postgresは、{"string1","string2","string3"}のようにフォーマットされた配列だけを受け取り、ARRAY['string1', 'string2', 'string3']ではないようです(下記参照)。以前の形式でエスケープする文字列は大きな痛みであり、Psycopg2のmogrify関数は後者の形式で配列を出力するため、これは問題です。最初の形式で手動でエスケープすることは私の最後の手段ですが、実際にそこに行きたくはありません。

Postgresをコピーやその他の回避策のために後者の形式にする方法はありますか?ここで

は私のテストです:

-- proof that both syntaxes are valid and compare equal 
db=# SELECT ARRAY['string1', 'string2', 'string3']::text[] = '{"string1","string2","string3"}'::text[]; 
?column? 
---------- 
t 
(1 row) 

-- COPY works with {} syntax 
db=# CREATE TEMP TABLE test(words text[]); 
CREATE TABLE 
db=# COPY test FROM stdin; 
Enter data to be copied followed by a newline. 
End with a backslash and a period on a line by itself. 
>> {"string1","string2","string3"} 
>> \. 
COPY 1 

-- COPY fails with ARRAY syntax 
db=# COPY test FROM stdin; 
Enter data to be copied followed by a newline. 
End with a backslash and a period on a line by itself. 
>> ARRAY['string1', 'string2', 'string3'] 
>> \. 
ERROR: malformed array literal: "ARRAY['string1', 'string2', 'string3']" 
DETAIL: Array value must start with "{" or dimension information. 
CONTEXT: COPY test, line 1, column words: "ARRAY['string1', 'string2', 'string3']" 
+0

ファイルを生成するために 'mogrify'を使用しています:

copy_values = cursor.mogrify(copy_values, data) 

copy_expertは、ファイルをエクスポートしますか? –

+0

いいえ、私はPythonの 'csv'ライターにデータを渡しています。ルールが異なるクエリ(例:文字列の一重引用符)のフォーマットを「曖昧にする」。私は配列の値に対して 'mogrify'を使ってみましたが、私が言ったように、' ARRAY'構文を私に与えます。 – sudo

答えて

2

あなたのデータタプルのリストを作成します:

data = [ 
    (1, ['a','b']), 
    (2, ['c','d']) 
] 

は、データタプルを受け取るためにvalues構文テンプレートを作成します。copyコマンドに

values_template = ','.join(['%s'] * len(data)) 

置き、それを:

copy_values = "copy (values {0}) to stdout (format csv)".format(values_template) 

mogrifyを使用して、Pythonの型をPostgresqに適合させますLタイプ:

f = open('file.csv', 'wb') 
cursor.copy_expert(copy_values, f, size=8192) 
f.close() 
+0

ああ、解決しました!これはすばらしい回避策です。奇妙なことに、たとえ値をstdoutにコピーしてデバッグしていたとしても、私はそれを考えなかった。 Pythonプロジェクトでは、コピーするファイルに書き込む 'COPY'ユーティリティがあります。この方法でそれを変更します。 – sudo

+0

一つの欠点は、少なくとも私のセットアップ(マシン上のデータベースローカル)では、Pythonの 'csv'ライブラリよりも遅いということです。 – sudo

1

最初のテスト(証拠)が本当に正しいではありません。この場合、これはテストでなければなりません。

SELECT 'ARRAY["string1", "string2", "string3"]'::text[] = '{"string1","string2","string3"}'::text[] 

これは機能しません。だから、私はこのフォーマットをCOPY FROM stdinに使うことはできないと思います。

+0

{}構文では、クエリ内でそれを囲む単一引用符が必要であり、 'ARRAY 'はそうではありません。 'SELECT 'ARRAY [" string1 "、" string2 "、" string3 "]' :: text [];'はエラーを返します。しかし、{}構文では、CSVからコピーするときに一重引用符は必要ありません。 – sudo

+1

それはまさに問題です。 stdinから読み込むと、引用符で囲まれた文字列であるかのように動作しますので、エラーが発生します。 –

+0

ああ、そうだ。ありがとう。私はこれを行う別の方法を見つける必要があるように見えます。 – sudo

関連する問題