2010-09-20 74 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