문제

나는 사용 중입니다 우분투 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

나는 pyodbc 개정을 잡았다 31e2fae4adbf1b2af1726e5668a3414cf46b454f ~에서 http://github.com/mkleehammer/pyodbc 그리고 "를 사용하여 설치했습니다"python setup.py install"

나는 Windows 기계가 있습니다 Microsoft SQL Server 2000 내 로컬 네트워크에 설치되어 로컬 IP 주소 10.32.42.69에서 청취. "Common"이라는 이름으로 만든 빈 데이터베이스가 있습니다. 전체 권한이있는 비밀번호 "비밀"이있는 사용자 "SA"가 있습니다.

다음 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

위의 모든 코드를 단일 파일로 넣었습니다. 여기, 도움을 원하는 사람을 쉽게 테스트 할 수 있습니다.

이제 질문을 위해 :

Python Code가 MSSQL에 이미지 파일을 삽입하려는 것을 원합니다. 이미지를 다시 쿼리하고 사용자에게 표시하고 싶습니다.

MSSQL의 열 유형은 신경 쓰지 않습니다. 나는 "IMAGE"예제의 열 유형이지만, 뒤로 삽입 한 파일의 이진 데이터를 얻는 한 모든 이진/블로브 유형이 수행됩니다. Vinay Sajip은 아래에서 SQL Server 2000에서 선호하는 데이터 유형이라고 아래에서 말했습니다.

이제 데이터가 오류없이 삽입되고 있지만 데이터를 검색하면 4K 만 반환됩니다. (데이터는 4096에 잘린다).

그 일을하려면 어떻게해야합니까?


편집: Vinay Sajip의 아래 답변은 필드에서 pyodbc.binary를 사용하는 힌트를주었습니다. 그에 따라 질문을 업데이트했습니다. 감사합니다 Vinay Sajip!

Alex Martelli의 의견은 DATALENGTH MS SQL 기능 데이터가 열에 완전히로드되어 있는지 테스트합니다. 감사합니다 Alex Martelli!

도움이 되었습니까?

해결책

허, 바운티를 제공 한 직후, 나는 해결책을 찾았다.

당신은 사용해야합니다 SET TEXTSIZE 2147483647 쿼리에서 텍스트 크기 구성 옵션 외에 /etc/freetds/freetds.conf.

나는 사용했다

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

그리고 모든 것이 잘 작동했습니다.

이상한 것은 무엇입니다 freetds 문서에 따르면 텍스트 크기 구성 옵션 :

기본값 TEXTSIZE, 바이트. 을 위한 text 그리고 image 데이터 유형은 반환 된 열의 최대 너비를 설정합니다. cf. set TEXTSIZE 에서 T-SQL 서버에 대한 문서.

구성에 따르면 최대 값 (및 기본값)은 4,294,967,295라고합니다. 그러나 쿼리에서 해당 값을 사용하려고 할 때 쿼리에서 사용할 수있는 최대 번호는 2,147,483,647 (절반)입니다.

그 설명에서 나는이 구성 옵션을 설정하는 것만으로 충분하다고 생각했다. 쿼리에서 텍스트를 설정하면 문제가 해결되었습니다.

아래는 전체 작업 코드입니다.

#!/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

다른 팁

나는 당신이 a를 사용해야한다고 생각합니다 pyodbc.Binary 데이터를 랩핑하는 인스턴스 :

cur.execute('INSERT INTO testing (myimage) VALUES (?)', (pyodbc.Binary(data),))

검색해야합니다

cur.execute('SELECT myimage FROM testing')
print "image bytes: %r" % str(cur.fetchall()[0][0])

업데이트: 문제는 삽입입니다. 삽입 SQL을 다음으로 변경하십시오.

"""DECLARE @txtptr varbinary(16)

INSERT INTO testing (myimage) VALUES ('')
SELECT @txtptr = TEXTPTR(myimage) FROM testing 
WRITETEXT testing.myimage @txtptr ?
"""

또한 검색 코드에서 값 속성을 사용하는 실수를 업데이트했습니다.

이 변경을 통해 320K JPEG 이미지를 데이터베이스에 삽입하고 검색 할 수 있습니다 (검색된 데이터는 삽입 된 데이터와 동일합니다).

nb image 데이터 유형은 더 이상 사용되지 않으며 대체됩니다 varbinary(max) 이후 버전의 SQL Server. 그러나 삽입/검색에 대한 동일한 논리는 최신 열 유형에 적용되어야합니다.

나는 비슷했다 4096 잘린 문제 TEXT 필드 SET TEXTSIZE 2147483647 나를 위해 고정되었지만 이것은 나에게도 고정되었습니다.

import os
os.environ['TDSVER'] = '8.0'
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top