2016-08-18 57 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'生成文件? –

+0

不,我將數據傳遞給Python的'csv'作家。用於查詢的'mogrify'格式,它具有不同的規則(例如,圍繞字符串的單引號)。我曾嘗試使用'mogrify'作爲數組值,但正如我所說的,它給了我'ARRAY'語法。 – sudo

回答

2

讓您的數據元組的列表:

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

創建values語法模板接收數據元組:

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

把它放到一個copy命令:

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

使用mogrify來使Python類型適應Postgresq升類型:

copy_values = cursor.mogrify(copy_values, data) 

copy_expert導出文件:

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

啊,解決了!這是一個很酷的解決方法。奇怪的是,即使我通過將值複製到標準輸出來調試,我從來沒有想過它。我在我的Python項目中有一個「COPY」實用程序,它寫入一個要複製的文件,我將通過這種方式進行更改。 – sudo

+0

一個缺點是,這比Python的'csv'庫慢,至少使用我的設置(數據庫在本地機器上)。 – sudo

1

第一個測試(證明)是不是真的正確。在這種情況下,這應該是測試:

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

並且不起作用。所以我會假設不,這種格式不能用於複製標準輸入。

+0

{}語法期望在查詢中包含它的單引號,而「ARRAY」不包含。 'SELECT'ARRAY [「string1」,「string2」,「string3」]':: text [];'返回一個錯誤。但從CSV複製時,{}語法不期望單引號。 – sudo

+1

這正是問題所在。當你從標準輸入讀取它時,它的行爲就像是一個帶引號的字符串,所以最終會出現錯誤。 –

+0

啊,我明白了。謝謝。看起來我必須找到另一種方式來做到這一點。 – sudo