Pyodbc + FreeTDS + SQL 服务器 + unicode 字符插入到 python 2.7 问题中的 nvarchar 列 - 'HY000',
Pyodbc + FreeTDS + SQL Server + unicode chars insert to nvarchar column in python 2.7 issue - 'HY000',
我在 python 2.7 中使用 pyodbc 将一些 unicode 字符插入 SQL 服务器中的 nvarchar
列。我没有成功。我对SQL服务器不是很熟悉。
我的代码:
import pyodbc
import string
import sys
import codecs
import os
import datetime
import time
def main(argv):
target_table = 'staging.sf.Account_test'
try:
reload(sys)
sys.setdefaultencoding('utf-8')
# sql server connection
sql_cnx = get_sql_server_connection()
sql_cur=sql_cnx.cursor()
sql_cur.execute('SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED')
# read from file
res_file_path = '/myfolder/test_double_byte_file.dat'
# write to sql server
write_data_to_sql_server(res_file_path, sql_cur, sql_cnx, target_table)
except:
e = sys.exc_info()
print "exception: %s" % e[1]
finally:
if 'sql_cnx' in locals():
sql_cnx.close()
def get_sql_server_connection():
connstring="driver=freeTDS;server=server;database=staging;uid=user;pwd=pwddd;port=1433;TDS_Version=8.0;CHARSET=UTF8;"
cnx=pyodbc.connect(connstring)
cnx.autocommit=True
return cnx
def write_data_to_sql_server(file_path, sql_cur, sql_cnx, target_table):
try:
f = codecs.open(file_path, 'r', encoding='utf-8')
csvread = csv.reader(f, delimiter='^')
lines=list(csvread)
values=""
numcols=len(lines[0])
wildcard='?,'
for i in range(numcols):
values = values + wildcard
values = values.strip(',')
insertstatement = "insert into "+target_table+" values("+values+")"
print insertstatement
sql_cur.execute("DELETE FROM " + target_table)
#sql_cnx.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8', to=str)
#sql_cnx.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8', to=unicode)
#sql_cnx.setencoding(str, encoding='utf-8')
#sql_cnx.setencoding(unicode, encoding='utf-8')
print "nlines:- "+str(len(lines))
#print "sleeping..."
#time.sleep(60)
batch = 20
while len(lines) > 0 :
rowarr = []
for row in lines[:batch]:
print "line:-"+ str(row)
tup = ()
col_cnt = 0
for col in row:
tup = tup + (str(row[col_cnt]).encode('utf-8'),)
print str(row[col_cnt]).encode('utf-8')
col_cnt = col_cnt + 1
rowarr.append(tup)
sql_cur.executemany(insertstatement, rowarr)
print 'commiting..'
sql_cnx.commit()
del lines[:batch]
except:
e = sys.exc_info()
print "exception: %s" % e[1]
if __name__ == "__main__": main(sys.argv[1:])
数据文件 - test_double_byte_file.dat
6-1-12, TANASHICHO^.^2017-08-09T21:02:26.000+0000
代々木2-28-7NTビル1階^株式会社ネクサスご担当者^2017-10-04T05:09:36.000+0000
北青山2-8-35^経理部^2017-08-09T21:03:12.000+0000
渋谷2-12-12 三貴ビル8F^経理部^2017-08-06T16:09:34.000+0000
南青山2-11-16 METLIFE青山ビル^経理部^2017-08-31T01:01:10.000+0000
3-2 TRⅡビル4F^茂代 髙月^2017-08-06T16:09:34.000+0000
中区丸の内3-21−21丸の内東桜ビル805^経理部^2017-08-19T04:01:41.000+0000
神宮前1-3-12ジブラルタ生命原宿ビル2F^UNKNOWN^2017-08-09T21:03:16.000+0000
銀座7-17-14松岡銀七ビル 5F^経理部^2017-09-25T10:20:47.000+0000
港南1-9-1NTT品川TWINSビル^経理部^2017-08-09T21:03:16.000+0000
日本橋本町1-9-4ヒューリック日本橋本町1町名ビル8階^経理部^2017-08-09T21:03:16.000+0000
错误:
exception: ('HY000', '[HY000] [FreeTDS][SQL Server]Unknown error (0) (SQLExecDirectW)')
不确定我错过了什么...
数据文件中不包含 unicode 字符的第一行可以正确插入。但其他线路抛出异常。
在此感谢任何帮助。
您的代码 returns 数据文件中的文本值作为 str
包含 UTF-8 编码字节的对象 ...
f = codecs.open(file_path, 'r', encoding='utf-8')
csvread = csv.reader(f, delimiter='^')
lines=list(csvread)
item = lines[1][0]
print(repr(item))
# '\xe4\xbb\xa3\xe3\x80\x85\xe6\x9c\xa82-28-7NT\xe3\x83\x93\xe3\x83\xab1\xe9\x9a\x8e'
... 对它们调用 encode
无效:
encoded_item = item.encode('utf-8')
print(repr(encoded_item))
# '\xe4\xbb\xa3\xe3\x80\x85\xe6\x9c\xa82-28-7NT\xe3\x83\x93\xe3\x83\xab1\xe9\x9a\x8e'
您真正想要做的是将它们解码为正确的 Unicode 对象...
decoded_item = item.decode('utf-8')
print(repr(decoded_item))
# u'\u4ee3\u3005\u67282-28-7NT\u30d3\u30eb1\u968e'
... 并将这些 Unicode 对象作为参数值传递。那是因为 SQL 服务器不使用 UTF-8 编码——它使用 UTF-16LE——并且 pyodbc 可以采用 Unicode object(它独立于任何特定的 encoding) 并以可接受的格式将其传递给 ODBC 驱动程序。
顺便说一句,通过...更改默认编码
reload(sys)
sys.setdefaultencoding('utf-8')
... 被认为是有风险的,因为它可以破坏依赖于 Python2 ('ascii') 的实际默认编码的东西。最好使用
的方法读取 Unicode "CSV" 文件
- 不会破解 Python2 和
的默认编码
- returns 正确的 Unicode 对象。
我在 python 2.7 中使用 pyodbc 将一些 unicode 字符插入 SQL 服务器中的 nvarchar
列。我没有成功。我对SQL服务器不是很熟悉。
我的代码:
import pyodbc
import string
import sys
import codecs
import os
import datetime
import time
def main(argv):
target_table = 'staging.sf.Account_test'
try:
reload(sys)
sys.setdefaultencoding('utf-8')
# sql server connection
sql_cnx = get_sql_server_connection()
sql_cur=sql_cnx.cursor()
sql_cur.execute('SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED')
# read from file
res_file_path = '/myfolder/test_double_byte_file.dat'
# write to sql server
write_data_to_sql_server(res_file_path, sql_cur, sql_cnx, target_table)
except:
e = sys.exc_info()
print "exception: %s" % e[1]
finally:
if 'sql_cnx' in locals():
sql_cnx.close()
def get_sql_server_connection():
connstring="driver=freeTDS;server=server;database=staging;uid=user;pwd=pwddd;port=1433;TDS_Version=8.0;CHARSET=UTF8;"
cnx=pyodbc.connect(connstring)
cnx.autocommit=True
return cnx
def write_data_to_sql_server(file_path, sql_cur, sql_cnx, target_table):
try:
f = codecs.open(file_path, 'r', encoding='utf-8')
csvread = csv.reader(f, delimiter='^')
lines=list(csvread)
values=""
numcols=len(lines[0])
wildcard='?,'
for i in range(numcols):
values = values + wildcard
values = values.strip(',')
insertstatement = "insert into "+target_table+" values("+values+")"
print insertstatement
sql_cur.execute("DELETE FROM " + target_table)
#sql_cnx.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8', to=str)
#sql_cnx.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8', to=unicode)
#sql_cnx.setencoding(str, encoding='utf-8')
#sql_cnx.setencoding(unicode, encoding='utf-8')
print "nlines:- "+str(len(lines))
#print "sleeping..."
#time.sleep(60)
batch = 20
while len(lines) > 0 :
rowarr = []
for row in lines[:batch]:
print "line:-"+ str(row)
tup = ()
col_cnt = 0
for col in row:
tup = tup + (str(row[col_cnt]).encode('utf-8'),)
print str(row[col_cnt]).encode('utf-8')
col_cnt = col_cnt + 1
rowarr.append(tup)
sql_cur.executemany(insertstatement, rowarr)
print 'commiting..'
sql_cnx.commit()
del lines[:batch]
except:
e = sys.exc_info()
print "exception: %s" % e[1]
if __name__ == "__main__": main(sys.argv[1:])
数据文件 - test_double_byte_file.dat
6-1-12, TANASHICHO^.^2017-08-09T21:02:26.000+0000
代々木2-28-7NTビル1階^株式会社ネクサスご担当者^2017-10-04T05:09:36.000+0000
北青山2-8-35^経理部^2017-08-09T21:03:12.000+0000
渋谷2-12-12 三貴ビル8F^経理部^2017-08-06T16:09:34.000+0000
南青山2-11-16 METLIFE青山ビル^経理部^2017-08-31T01:01:10.000+0000
3-2 TRⅡビル4F^茂代 髙月^2017-08-06T16:09:34.000+0000
中区丸の内3-21−21丸の内東桜ビル805^経理部^2017-08-19T04:01:41.000+0000
神宮前1-3-12ジブラルタ生命原宿ビル2F^UNKNOWN^2017-08-09T21:03:16.000+0000
銀座7-17-14松岡銀七ビル 5F^経理部^2017-09-25T10:20:47.000+0000
港南1-9-1NTT品川TWINSビル^経理部^2017-08-09T21:03:16.000+0000
日本橋本町1-9-4ヒューリック日本橋本町1町名ビル8階^経理部^2017-08-09T21:03:16.000+0000
错误:
exception: ('HY000', '[HY000] [FreeTDS][SQL Server]Unknown error (0) (SQLExecDirectW)')
不确定我错过了什么...
数据文件中不包含 unicode 字符的第一行可以正确插入。但其他线路抛出异常。
在此感谢任何帮助。
您的代码 returns 数据文件中的文本值作为 str
包含 UTF-8 编码字节的对象 ...
f = codecs.open(file_path, 'r', encoding='utf-8')
csvread = csv.reader(f, delimiter='^')
lines=list(csvread)
item = lines[1][0]
print(repr(item))
# '\xe4\xbb\xa3\xe3\x80\x85\xe6\x9c\xa82-28-7NT\xe3\x83\x93\xe3\x83\xab1\xe9\x9a\x8e'
... 对它们调用 encode
无效:
encoded_item = item.encode('utf-8')
print(repr(encoded_item))
# '\xe4\xbb\xa3\xe3\x80\x85\xe6\x9c\xa82-28-7NT\xe3\x83\x93\xe3\x83\xab1\xe9\x9a\x8e'
您真正想要做的是将它们解码为正确的 Unicode 对象...
decoded_item = item.decode('utf-8')
print(repr(decoded_item))
# u'\u4ee3\u3005\u67282-28-7NT\u30d3\u30eb1\u968e'
... 并将这些 Unicode 对象作为参数值传递。那是因为 SQL 服务器不使用 UTF-8 编码——它使用 UTF-16LE——并且 pyodbc 可以采用 Unicode object(它独立于任何特定的 encoding) 并以可接受的格式将其传递给 ODBC 驱动程序。
顺便说一句,通过...更改默认编码
reload(sys)
sys.setdefaultencoding('utf-8')
... 被认为是有风险的,因为它可以破坏依赖于 Python2 ('ascii') 的实际默认编码的东西。最好使用
的方法读取 Unicode "CSV" 文件- 不会破解 Python2 和 的默认编码
- returns 正确的 Unicode 对象。