2010-09-20 46 views
4

我連接到通過SQL鍊金術一個MS SQL服務器調用,使用pyodbc模塊。一切似乎都工作正常,直到我開始有問題的編碼。一些非ASCII字符正在被替換爲'?'編碼從pyodbc到MS SQL Server的

數據庫都有一個歸類「Latin1_General_CI_AS」(我也檢查了特定的領域和他們保持相同的排序規則)。我開始在create_engine的調用中選擇編碼「latin1」,似乎適用於西歐字符(如法語或西班牙語,字符如é),但不適用於復活節歐洲字符。具體來說,我有性格ć

我一直在試圖選擇像cp1250cp1252其他編碼as stated on Python documentation,特別是微軟的,出了問題,但我一直面臨着同樣的問題。

有誰知道如何解決這些分歧?排序規則'Latin1_General_CI_AS'是否與Python編碼具有同等效果?

我的當前連接的代碼如下

for sqlalchemy import * 

def connect(): 
    return pyodbc.connect('DSN=database;UID=uid;PWD=password') 

engine = create_engine('mssql://', creator=connect, encoding='latin1') 
connection = engine.connect() 

澄清和評論:

  • 這個問題從檢索數據庫信息時發生的情況。我不需要存儲任何東西。
  • 開始時我沒有指定編碼,結果是,只要在數據庫上遇到非ascii字符,pyodbc就會引發UnicodeDecodeError。我糾正了使用'latin1'作爲編碼,但這並不能解決所有字符的問題。
  • 我承認服務器不在latin1上,評論是不正確的。我一直在檢查數據庫排序規則和特定字段排序規則,並且似乎都在'Latin1_General_CI_AS'中,那麼ć如何存儲?也許我沒有正確理解排序規則。
  • 我校正的小的問題,具體而言,我試圖更編碼比latin1,也cp1250cp1252(這顯然是對「Latin1_General_CI_AS」所使用的一個,根據MSDN)

UPDATE:

OK,按照以下步驟,我得到DB使用的編碼看起來是cp1252:http://bytes.com/topic/sql-server/answers/142972-characters-encoding 無論如何,這似乎是一個壞的假設,反映在答案上。

UPDATE2: 無論如何,在正確配置odbc驅動程序之後,我不需要在Python代碼中指定編碼。

+0

請澄清您的問題:在從數據庫獲取數據或將數據存儲到數據庫或應用程序交互期間,會發生這些替換嗎? 'Latin1_General_CI_AS'應該是'cp1252' – knitti 2010-09-20 11:22:04

+0

cp1250和cp1252不是「latin1編碼」。排序規則不是編碼。請回復您的評論:誰說「服務器以latin1編碼」?如果服務器希望所有的輸入/輸出都用latin1編碼(我懷疑),那麼你根本無法將一些東歐字符輸入到你的數據庫(也就是俄文,中文,希臘文等等)。 – 2010-09-20 11:24:52

+0

這個http://msdn.microsoft.com/en-us/library/ms174596(v=SQL.90).aspx建議,對於Latin1_General_CI_AS使用的編碼是cp1252。當然,'latin1'!='cp1252' – knitti 2010-09-20 11:32:08

回答

2

應停止使用代碼頁,並切換到Unicode。這是只有擺脫這種問題的方法。

+1

不幸的是,我們無法控制該數據庫,因此我們無法確定數據的存儲方式:-( – Khelben 2010-09-20 12:22:14

+0

這是否與您的問題相關http://code.google.com/p/pyodbc/issues/detail?id = 52?檢查你的ODBC提供程序是如何配置的,也許你可以保證編碼從那裏改變。不要忘記測試這些外部pyodbc。 – sorin 2010-09-20 12:42:44

+1

是的,就是這樣!問題是我沒有配置UTF -8模式我必須在/etc/freetds.conf文件的配置中添加'client charset = UTF-8' – Khelben 2010-09-20 14:00:05

0

好的,按照http://msdn.microsoft.com/en-us/library/ms174596(v=SQL.90).aspx編碼的Latin1_General_CI_AS最有可能是cp1252。所以,你必須使用encoding='cp1252'。但是這隻能解決問題的一半,因爲你的以某種方式輸出值來查看這些字符是否存在。因此,如果您有從數據庫中提取的some_db_value,則必須使用some_db_value.encode('proper-output-encoding')才能使其正確。 proper-output-encoding取決於,你如何輸出:在控制檯上,它是控制檯編碼,可以是'cp1252','cp437','cp850'(在窗口上)。在網絡上,它是網絡服務器的編碼,希望是'utf-8'。

編輯:請閱讀John Machin's answer,因爲它是不清楚是否「CP1252」是正確的數據庫編碼

1

嘗試連接到數據庫與pyodbc.connect()參數convert_unicode=True,例如。從SQLAlchemy的:

engine = create_engine('mssql://yourdb', connect_args={'convert_unicode': True}) 

這應該確保所有的結果(而不僅是那些從nvarchar等...)你得到的是unicode的,正確地從任何編碼在DB使用轉換。

至於寫入數據庫,只是總是使用Unicode。如果我沒有弄錯(稍後會檢查),pyodbc會確保它也會正確寫入數據庫。 (當然,如果數據庫使用的編碼不支持您要編寫的字符,您仍然會遇到錯誤:如果您希望列支持任何種類的字符,則必須使用unicode列在DB過)

2

原文評論變成了一個答案:

CP1250和CP1252不是 「latin1的編碼」。排序規則不是編碼。請回復您的評論:誰說「服務器以latin1編碼」?如果服務器希望所有的輸入/輸出都用latin1編碼(我懷疑),那麼你根本無法將一些東歐字符輸入到你的數據庫(也就是俄文,中文,希臘文等等)。

更新

你需要更遠的地方看起來比歸類。 msdn.microsoft.com/en-us/library/ms174596(v=SQL.90).aspx表明,對於Latin1_General_CI_AS,使用的編碼是cp1252「」「是codswallop。該表提供LCID(區域設置ID),默認排序和每個語言環境的代碼頁。是的,排序「Latin1_General_CI_AS」與幾個語言環境的cp1252代碼頁相關聯列出。對於兩個語言環境(亞美尼亞語和格魯吉亞語),它與「Unicode」代碼頁(!!!)一起列出。

很簡單,你需要找出數據庫正在使用的代碼頁

嘗試從數據庫提取數據而不指定編碼。 不要麻煩編碼,你猜你的控制檯可能會使用任何編碼 - 這隻會增加另一個混淆源。相反,使用print repr(data)。在這裏報告你從repr()中得到了你期望非Latin1字符的地方。

+0

+1你說的沒錯,完全閱讀。 – knitti 2010-09-20 13:10:00