python - 在 ubuntu 上使用 pyodbc 在 SQL Server 上插入图像字段

标签 python sql-server image pyodbc freetds

我正在使用 Ubuntu 9.04

我已经安装了以下软件包版本:

unixodbc and unixodbc-dev: 2.2.11-16build3
tdsodbc: 0.82-4
libsybdb5: 0.82-4
freetds-common and freetds-dev: 0.82-4
python2.6-dev

我已经像这样配置了 /etc/unixodbc.ini:

[FreeTDS]
Description             = TDS driver (Sybase/MS SQL)
Driver          = /usr/lib/odbc/libtdsodbc.so
Setup           = /usr/lib/odbc/libtdsS.so
CPTimeout               = 
CPReuse         = 
UsageCount              = 2

我已经像这样配置了 /etc/freetds/freetds.conf:

[global]
    tds version = 8.0
    client charset = UTF-8
    text size = 4294967295

我从 http://github.com/mkleehammer/pyodbc 抓取了 pyodbc 修订版 31e2fae4adbf1b2af1726e5668a3414cf46b454f 并使用“python setup.py install"

我在本地网络上安装了一台装有 Microsoft SQL Server 2000 的 Windows 计算机,启动并监听本地 IP 地址 10.32.42.69。我创建了一个名为“Common”的空数据库。我的用户“sa”和密码“secret”具有完全权限。

我正在使用以下 python 代码来设置连接:

import pyodbc
odbcstring = "SERVER=10.32.42.69;UID=sa;PWD=secret;DATABASE=Common;DRIVER=FreeTDS"
con = pyodbc.connect(odbcstring)
cur = con.cursor()

cur.execute("""
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
      WHERE TABLE_NAME = 'testing')
   DROP TABLE testing
""")
cur.execute('''
CREATE TABLE testing (
    id INTEGER NOT NULL IDENTITY(1,1), 
    myimage IMAGE NULL, 
    PRIMARY KEY (id)
)
    ''')
con.commit()

到目前为止,一切都有效。我在服务器上使用了 SQLServer 的企业管理器,新表就在那里。 现在我想在表中插入一些数据。

cur = con.cursor()
# using web data for exact reproduction of the error by all.
# I'm actually reading a local file in my real code.
url = 'http://www.forestwander.com/wp-content/original/2009_02/west-virginia-mountains.jpg'
data = urllib2.urlopen(url).read()

sql = "INSERT INTO testing (myimage) VALUES (?)"

现在在我原来的问题上,我在使用 cur.execute(sql, (data,)) 时遇到了问题,但现在我已经编辑了这个问题,因为下面是 Vinay Sajip 的回答(谢谢), 我已将其更改为:

cur.execute(sql, (pyodbc.Binary(data),)) 
con.commit()

并且插入运行良好。我可以使用以下测试代码确认插入数据的大小:

cur.execute('SELECT DATALENGTH(myimage) FROM testing WHERE id = 1')
data_inside = cur.fetchone()[0]
assert data_inside == len(data)

完美通过了!!!

现在的问题是取回数据。

我正在尝试常见的方法:

cur.execute('SELECT myimage FROM testing WHERE id = 1')
result = cur.fetchone()
returned_data = str(result[0]) # transforming buffer object
print 'Original: %d; Returned: %d' % (len(data), len(returned_data))
assert data == returned_data

然而失败了!!

Original: 4744611; Returned: 4096
Traceback (most recent call last):
  File "/home/nosklo/devel/teste_mssql_pyodbc_unicode.py", line 53, in <module>
    assert data == returned_data
AssertionError

我已将上面的所有代码放在一个文件中 here ,以便轻松测试任何想要提供帮助的人。

现在是问题:

我想要 python 代码将图像文件插入到 mssql 中。我想查询回图像并将其显示给用户。

我不关心 mssql 中的列类型。我在示例中使用的是“IMAGE”列类型,但任何二进制/blob 类型都可以,只要我得到未损坏的文件的二进制数据即可。 Vinay Sajip 在下面说这是 SQL SERVER 2000 中首选的数据类型。

数据现在正在无误地插入,但是当我检索数据时,只返回 4k。 (数据在 4096 处被截断)。

我怎样才能让它发挥作用?


编辑:下面 Vinay Sajip 的回答给了我在该领域使用 pyodbc.Binary 的提示。我已经相应地更新了问题。谢谢 Vinay Sajip!

Alex Martelli 的评论让我想到了使用 DATALENGTH MS SQL 函数来测试数据是否已完全加载到列中。谢谢 Alex Martelli!

最佳答案

嗯,刚刚悬赏之后,我找到了解决方案。

除了 /etc/freetds/freetds.conf 中的文本大小配置选项外,您还必须在查询中使用 SET TEXTSIZE 2147483647

我用过

cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')

一切正常。

奇怪的是FreeTDS documentation says关于文本大小配置选项:

default value of TEXTSIZE, in bytes. For text and image datatypes, sets the maximum width of any returned column. Cf. set TEXTSIZE in the T-SQL documentation for your server.

配置还指出最大值(默认值)为 4,294,967,295。但是,当尝试在查询中使用该值时出现错误,我可以在查询中使用的最大数量是 2,147,483,647(一半)。

根据该解释,我认为仅设置此配置选项就足够了。事实证明我错了,在查询中设置 TEXTSIZE 解决了这个问题。

下面是完整的工作代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyodbc
import urllib2

odbcstring = "SERVER=10.32.42.69;UID=sa;PWD=secret;DATABASE=Common;DRIVER=FreeTDS"
con = pyodbc.connect(odbcstring)
cur = con.cursor()

cur.execute("""
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
      WHERE TABLE_NAME = 'testing')
   DROP TABLE testing
""")

cur.execute('''
CREATE TABLE testing (
    id INTEGER NOT NULL IDENTITY(1,1), 
    myimage IMAGE NULL,
    PRIMARY KEY (id)
)
    ''')

con.commit()
cur = con.cursor()
url = 'http://www.forestwander.com/wp-content/original/2009_02/west-virginia-mountains.jpg'
data = urllib2.urlopen(url).read()

sql = "INSERT INTO testing (myimage) VALUES (?)"
cur.execute(sql, (pyodbc.Binary(data),))
con.commit()

cur.execute('SELECT DATALENGTH(myimage) FROM testing WHERE id = 1')
data_inside = cur.fetchone()[0]
assert data_inside == len(data)

cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')
result = cur.fetchone()
returned_data = str(result[0])
print 'Original: %d; Returned; %d' % (len(data), len(returned_data))
assert data == returned_data

关于python - 在 ubuntu 上使用 pyodbc 在 SQL Server 上插入图像字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1060035/

相关文章:

python - Groupby 两列和一列行的比较

python - 如何在没有 rhc 端口转发的情况下在 OpenShift 上访问 MySQL?

html - Bootstrap 4 图像缩略图类

c# - 哪种解决方案更适合从数据库获取随机记录集?

Javascript 声音开始/停止和图像变化

html - 图像缩放问题(尺寸缩小质量损失)

python - 从 numpy 数组中删除元素时跟踪删除的索引

python - 熊 : change FirstPersonController controls

sql-server - 创建一个存储过程来聚合行

sql-server - 当删除行时,SQL 触发器中的 UPDATED() 函数是否返回 true?