gpt4 book ai didi

Python通过pyodbc在Access中的十进制数中插入一个冒号

转载 作者:太空狗 更新时间:2023-10-30 01:34:37 26 4
gpt4 key购买 nike

我有 same problem as this guy可能还有 this guy ,但我会分享一些代码并回答问题!

我在批处理作业中有一些代码通过 pyodbc 从 Microsoft Access 数据库读取字段并准备输出以供显示。

这是一个片段。注意断言。

def format_currency(amount):
if amount is None:
return ""
else:
result = "$%.2f" % amount
assert ":" not in result, (
"That's weird. The value %r of class %s is represented as %s" %
(amount, amount.__class__, result))
return result

当我运行它时,它成功处理了 100,000 行然后失败了:

AssertionError: That's weird. The value Decimal('54871.0000') of class <class
'decimal.Decimal'> is represented as $54870.:0

注意异常冒号。它很少发生 - 大约每 300,000 条记录出现一次。

当我尝试隔离它时,它当然有效。

from decimal import Decimal
print "$%.2f" % Decimal('54871.0000')

$54871.00

Access 中字段的类型是:

  • 数据类型:货币
  • 小数位数:2
  • 输入掩码:
  • 默认值:
  • 验证规则:
  • 文本对齐:常规

我基于不充分证据的模糊指责怀疑:pyodbc 正在戳破 Decimal 的内部结构,可能被 Access 损坏所混淆。作为@ecatmur points out :

':' is '9' + 1 in ASCII

有人看到并解决了吗?

版本:

  • python 2.7.4
  • pyodbc 3.0.6(最新)
  • Access 2010
  • Windows 7

进一步挖掘:

decimal 模块是用 Python 实现的。根据我的阅读,这些值由四个属性描述:_exp_int_sign_is_special

怀疑有损坏,我打印出了这些字段的值。

令人惊讶的是,对于 故障版本和工作版本,我得到:

_exp: -4
_int: 548710000
_sign: 0
_is_special: False

这很奇怪。


decimal 模块中,__float__ 函数的定义相当简单:

def __float__(self):
"""Float representation."""
return float(str(self))

但是当我对错误数据执行此操作时:

print "Str", str(amount)
print "Float", float(amount)

我得到:

Str 54871.0000

Float 54870.:

我学得越多,它就越不奇怪。

最佳答案

我能够重现错误。我创建了一个 Access 表 [pyData]...

ID - 自动编号
金额 - 货币(2 位小数)

...并用 50,000 到 60,000 之间的一百万行随机值填充它。当我运行我的测试脚本时,它在这里失败了

30815 : $50638.91
30816 : $52423.28
30817 :

Traceback (most recent call last):
File "C:\__tmp\pyOdbcTest.py", line 20, in <module>
print row.ID, ":", format_currency(row.Amount)
File "C:\__tmp\pyOdbcTest.py", line 10, in format_currency
(amount, amount.__class__, result))
AssertionError: That's weird. The value Decimal('58510.0000') of class <class 'decimal.Decimal'> is represented as $5850:.00

我还测试了该值 (58510.00) 和您失败的值 (54871.00) 作为具有相同结构的单独表中的单行,它们都失败了。所以我们知道它不是来自早期 ODBC 调用的一些剩余“垃圾”的函数。

考虑到它可能与数字末尾有一个“1”后跟零的数字有关,我尝试了 55871.00,但效果很好。 53871.00 也工作得很好。将数字改回 54871.00 后,错误又出现了。

我使用 pypyodbc 尝试了相同的测试并得到了同样的错误。我有点乐观,因为 pypyodbc 包含许多特定于 Access 的功能,所以我认为它的一位用户以前可能遇到过这个问题,但显然没有。

最后,我将我的测试表升级到 SQL Server 2008 R2 Express,并尝试使用 {SQL Server Native Client 10.0} 驱动程序进行相同的测试。从 Access(“货币”列类型)读取时失败的数字在从 SQL Server 表(“货币”列类型)读取时不会失败。

因此,目前我能提供的最佳“答案”是:

看起来是:

  • pyodbc(和 pypyodbc,它似乎与 pyodbc 密切相关)中的错误,或

  • Microsoft Access ODBC 驱动程序中的错误,或者

  • 两者之间的“不幸交互”(如果 ODBC 规范足够宽松以至于两个组件在技术上都不是“错误的”)。

无论如何,看起来您需要解决它,至少现在是这样。

编辑

由于我有那么多数字,所以我决定让脚本继续运行,看看其他哪些数字可能会被格式化为冒号。结果列表似乎都是整数(没有便士),所以我用 1 到 100,000 之间的整数进行了另一个测试。我发现 260 个数字在格式化字符串中以冒号结束:

1451.0000 -> $1450.:0
1701.0000 -> $1700.:0
1821.0000 -> $1820.:0
1951.0000 -> $1950.:0
2091.0000 -> $2090.:0
...
98621.0000 -> $98620.:0
98710.0000 -> $9870:.00
99871.0000 -> $99870.:0

我粘贴了整个列表 here .也许这会有所帮助。

编辑 - 问题已解决 (?)

我之前的测试是在 Python 2.7.3 版本下运行的。我刚刚将 Python 升级到 2.7.5 版(Win 32 位),而 pyodbc 仍然是 3.0.6 版,问题似乎已经消失。

关于Python通过pyodbc在Access中的十进制数中插入一个冒号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16612301/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com