为什么我的VARCHAR被截断为255个字符?我该如何解决这个问题?

时间:2017-10-11 00:45:46

标签: python sql-server-2012 sqlalchemy unixodbc

设定:

我使用以下组件:

  • unixODBC 2.3.4
  • FreeTDS 1.12
  • Python 3.6
  • SQLAlchemy的

...针对MSSQL Server 2014。

问题:

假设我有一个仅包含2列的表:

  • id(主键,int)
  • my_text(VARCHAR())

我的SQLAlchemy模型如下所示:

from sqlalchemy.dialects.mssql.base import VARCHAR

MyText(Base):
    id = Column(Integer, primary_key=True)
    my_text = Column(VARCHAR())

当我尝试创建一个这样的新文本条目,并且我的文本长度超过255个字符时,该字符串将在255处以静默方式截断。

my_text='REALLY LONG STRING THAT IS LONGER THAN 255. E.g.: 6000+ characters. Assume my string is 558 bp long.'
print(len(my_text))  # Gives 558 bp.
new_text = MyText(my_text=my_text)
print(len(new_text.my_text))  # Gives 558 bp.
db_s.add(new_text)
print(len(new_text.my_text))  # Gives 558 bp.
db_s.commit()
print(len(new_text.my_text))  # Gives 255 bp now after commit.

首先,我认为这是在DB写入时造成的。但我发现这是在查询时引起的(见下文)。

问题:

1。)为什么会发生这种情况?

我认为这与驱动程序有关(例如:unixodbc 2.3.4,FreeTDS 1.12),但我并不完全正是这种情况发生的地方。

2。)更重要的是,我该如何解决这个问题?

这些问题有关但不同:

MySQL VARCHAR index truncated to 255 during migration

上面的问题是我没有使用MYSQL。所以提供的解决方案无法解决问题。

unixODBC/FreeTDS results truncated to 255 character

该线程未提供解决方案。

就此而言,应该注意的是,我的字符串通常可以长达6000个字符(因为我使用的是长DNA序列)。我真的很感激任何解决截断问题的方法。

更新(2017-10-12):

自昨天以来,我做了一些非凡但同样令人费解的发现。

# Connecting via pyodbc direct connection using just some helper functions to make things more convenient.
con_str = create_connection_string(DATABASE='test')
cur = make_connection_db(connection_str=con_str)
for row in cur.execute('SELECT Text.my_text, len(Text.my_text) FROM [test].[dbo].[Text]'):
    print(row)
    print(len(row[0]))

这给了我一个长度为558个字符的字符串(见下文)。

 ('ATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATG', 
 558)
 558

现在使用SQL Alchemy但仍然直接使用sql语句。

# Using SqlAlchemy connection with direct SQL query.
eoi_engine = create_engine(
"mssql+pyodbc://user:somepw@db:1234/test?driver=FreeTDS")
s_con = eoi_engine.connect()
s_res = s_con.execute('SELECT Text.my_text, len(Text.my_text) FROM [test].[dbo].[Text]')
for row in s_res:
    print(row)
    print(len(row[0])

这给了我一个声称长度为558个字符的字符串,但实际上它只有255个字符。

 ('ATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATG', 
 558)
 255

最后一个场景:

# Using SQLAlchemy full-stack.
Session = sessionmaker()

s = Session(bind=s_con)
fs_res = s.query(DNAPtsSeq).filter().all()
for row in fs_res:
    print(row)
    print(len(row.nt_seq))

这给了一个长度只有255个字符的字符串。

总结如下:

  • 创建的原因不是在向DB写入内容时,而是在从DB字符中查询内容时会被静默截断。
  • 当我使用SQLAlchemy操作时,我只会遇到截断问题。

我不知道为什么我在使用SQLAlchemy查询时只会出现此错误。有谁知道原因?我该如何解决这个问题? (我知道解决方法是使用直接的SQL查询......)

2 个答案:

答案 0 :(得分:0)

在我的情况下,事实证明有几个复合错误,我列出后代,以防其他人遇到与我相同的问题:

  1. 当我最初创建表时,我没有将表声明为VARCHAR(MAX),而是将它们声明为VARCHAR(8000)。
  2. 当我在数据库中修复数据表时,我没有更改ORM。该领域仍然是VARCHAR(8000)。不知怎的,这会导致无声的截断。
  3. 即使将VARCHAR(8000)更改为VARCHAR()也无法解决问题。事实证明,MSSQL VARCHAR(MAX)非常不标准。一个不起眼的参考,让我发现只有MSSQL有一个不同的VARCHAR。如果从以下位置导入VARCHAR:

    from sqlalchemy.dialects.mssql.base import VARCHAR
    
  4. ...然后你可以将你的文本字段声明为VARCHAR(),它等于MSSQL中的VARCHAR(Max)。

    http://docs.sqlalchemy.org/en/latest/dialects/mssql.html

    这会将截断限制增加到4096个字符但未解决它。

    我试着在这里解读以下答案:

    SQLAlchemy Truncating VARCHAR(MAX)

    不幸的是,更改文本大小缓冲区不会删除4096的截断限制。在我的情况下,我还必须在SQLAlchemy的SQL语句中使用SQL语句之前的查询:

    db_s.execute('Set TEXTSIZE {0}'.format(SOME_BIG_NUMBER_LIKE_20000)
    

答案 1 :(得分:0)

感谢您的旧帖子

我的解决方案是在 SELECT 语句中使用 CAST(FIELDNAME as NVARCHAR(4000))

如果我使用 CAST(FIELDNAME as NVARCHAR),SQLAlchemy 会剪切字符串