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

Why is my VARCHAR truncated to 255 characters? How do I fix this?

设置:

我正在使用以下组件:

...针对 MSSQL Server 2014.

问题:

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

我的 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.

起初,我认为这是在写入数据库时​​造成的。但我发现这是在查询时造成的(阅读下文)。

问题:

1.) 为什么会这样?

我认为这与驱动程序有关(例如:unixodbc 2.3.4、FreeTDS 1.12),但我并不完全了解发生这种情况的原因。

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

这些问题既相关又不同:

上面的问题是我没有使用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 个字符长的字符串。

所以总结一下:

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

在我的例子中,事实证明有几个复合错误,我列出来以防其他人 运行 遇到与我相同的问题:

  1. 当我最初创建 table 时,我没有将 table 声明为 VARCHAR(MAX),而是将它们声明为 VARCHAR(8000)。
  2. 当我修复数据库中的数据table时,我没有更改ORM。该字段仍然是 VARCHAR(8000)。不知何故,这导致了沉默的 t运行cation。
  3. 即使将 VARCHAR(8000) 更改为 VARCHAR() 也没有解决我的问题。事实证明,MSSQL VARCHAR(MAX) 是高度不标准的。一个晦涩的参考,让我发现有一个不同的 VARCHAR 只适用于 MSSQL。如果从以下位置导入 VARCHAR:

    from sqlalchemy.dialects.mssql.base import VARCHAR
    

...然后您可以将文本字段声明为 VARCHAR(),这在 MSSQL 中等于 VARCHAR(Max)。

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

这已将 t运行cation 限制增加到 4096 个字符,但没有解决它。

我试图在这里破译以下答案:

SQLAlchemy Truncating VARCHAR(MAX)

不幸的是,更改文本大小缓冲区不会删除 4096 的 t运行 阳离子限制。在我的情况下,我还必须在查询数据库之前使用来自 SQLAlchemy 的 sql 语句:

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

感谢老post

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

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