MSSQL pyodbc 插入失败,因为计算机表示范围不足(8字节)。

huangapple go评论72阅读模式
英文:

MSSQL pyodbc insert failing due to range of computer representation (8 bytes)

问题

以下是您要翻译的内容:

错误信息是:
"pyodbc.DataError: ('22003', "[22003] [Microsoft][ODBC SQL Server Driver][SQL Server]The floating point value '9786E' is out of the range of computer representation (8 bytes)."

所以基本上,如果我去掉值前面的“OI-”,那么就没问题了。

值的类型是字符串。
尝试过在MSSQL中将列类型设置为varchar(max),nvarchar(max),text等等。

英文:

Can someone help me how to insert"OI-9786E543971246B29470AFA10414A1E2" value as a string to MSSQL db in python?

Error I get is:
"pyodbc.DataError: ('22003', "[22003] [Microsoft][ODBC SQL Server Driver][SQL Server]The floating point value '9786E' is out of the range of computer representation (8 bytes)."

        for client in clients:
            counts += 1
            insert_stmt += f"INSERT INTO [x].[dbo].[x] ([commcell],[clientName],[clientDisplayName],[clientHostName],[instanceId]) VALUES ('{client['commcell']}','{client['clientName']}','{client['clientDisplayName']}','{client['clientHostName']}','{client['instanceId']}') \r\n"
            if counts % 300 == 0:
                insert_stmt += "COMMIT TRANSACTION"
                cursor.execute(insert_stmt)
                cursor.commit()
                insert_stmt = "BEGIN TRANSACTION \r\n"
        if insert_stmt != "BEGIN TRANSACTION \r\n":
            insert_stmt += "COMMIT TRANSACTION"
            cursor.execute(insert_stmt)
            cursor.commit()

So basically if I would to remove OI- at the front of the value it would be ok..

Type of the value is string.
Tried column types in MSSQL to be as varchar(max), nvarchar(max), text and so on.

答案1

得分: 2

通过这种方式连接字符串,你正在对自己的代码进行SQL注入攻击。

SQL Server的插入行在SQL Server的概念验证教程中展示了如何安全地传递值给任何SQL查询,而不仅仅是对SQL Server的INSERT操作:

#示例插入查询
sql = """
INSERT INTO SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) 
VALUES (?,?,?,?,?)
"""

count = cursor.execute(sql,
'SQL Server Express New 20', 'SQLEXPRESS New 20', 0, 0, CURRENT_TIMESTAMP).rowcount
cnxn.commit()
print('Rows inserted: ' + str(count))

我稍微修改了示例以明确SQL查询不包括任何值。这也不是格式化字符串。参数值从不成为查询本身的一部分。它们被发送到数据库服务器,只在查询被编译成执行计划之后使用。

至少,Python代码应该更改为以下内容:

sql = """
    INSERT INTO [x].[dbo].[x] ([commcell],[clientName],[clientDisplayName],[clientHostName],[instanceId]) 
    VALUES (?,?,?,?,?) 
"""

count = cursor.execute(sql,
    client['commcell'], 
    client['clientName'], 
    client['clientDisplayName'], 
    client['clientHostName'], 
    client['instanceId'])
...

还可以使用executemany一次插入多行,并设置cursor.fast_executemany = True

cursor.fast_executemany = True
..
tuples=[('foo','bar', 'ham'), ('hoo','far', 'bam')]
cursor.executemany(sql, tuples)
cursor.commit()

这将将所有值缓存在内存中,并一次性发送到服务器。

英文:

By concatenating strings this way you're causing a SQL injection attack against your own code.

The Insert a row in SQL Server's proof-of-concept tutorial shows how to safely pass values to any SQL query, not just INSERTs against SQL Server:

#Sample insert query
sql="""
INSERT INTO SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) 
VALUES (?,?,?,?,?)"""

count = cursor.execute(sql,
'SQL Server Express New 20', 'SQLEXPRESS New 20', 0, 0, CURRENT_TIMESTAMP).rowcount
cnxn.commit()
print('Rows inserted: ' + str(count))

I modified the example a bit to make it clear that the SQL query doesn't include any values. This isn't a format string either. The parameter values never become part of the query itself. They're sent to the database server and used only after the query gets compiled into an execution plan.

At the very least, the python code should change to this:

sql = """
    INSERT INTO [x].[dbo].[x] ([commcell],[clientName],[clientDisplayName],[clientHostName],[instanceId]) "
    VALUES (?,?,?,?,?) 
"""

count = cursor.execute(sql,
    client['commcell'], 
    client['clientName'], 
    client['clientDisplayName'], 
    client['clientHostName'], 
    client['instanceId'])
...

It's also possible to insert multiple rows at a time using executemany and setting cursor.fast_executemany = True :

cursor.fast_executemany = True
..
tuples=[('foo','bar', 'ham'), ('hoo','far', 'bam')]
cursor.executemany(sql, tuples)
cursor.commit()

This caches all values in memory and sends all of them at once to the server

huangapple
  • 本文由 发表于 2023年7月3日 21:39:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605290.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定