Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将Python十进制转换为SQLite数字?_Python_Sqlite_Decimal_Numeric - Fatal编程技术网

如何将Python十进制转换为SQLite数字?

如何将Python十进制转换为SQLite数字?,python,sqlite,decimal,numeric,Python,Sqlite,Decimal,Numeric,我有一个程序,可以读取JSON格式的财务数据并将其插入SQLite数据库。问题是当我将它插入SQLite数值列时,它似乎不喜欢这个对象 我发现了这个问题,但答案已经过时,据我所知,SQLite现在有了一个货币数据类型 现在作为一种解决方法,我将十进制值存储为文本,但是否可以将其存储为数字?对于数据库插入和财务计算,我是否被小数转换为字符串,反之亦然的开销所困扰?至少你链接到的页面没有提到货币数据类型,并且只打开了数值关联 如果它是我的数据,我可能会存储一个整数的货币“单位”——便士,或十分之一便

我有一个程序,可以读取JSON格式的财务数据并将其插入SQLite数据库。问题是当我将它插入SQLite数值列时,它似乎不喜欢这个对象

我发现了这个问题,但答案已经过时,据我所知,SQLite现在有了一个货币数据类型


现在作为一种解决方法,我将十进制值存储为文本,但是否可以将其存储为数字?对于数据库插入和财务计算,我是否被小数转换为字符串,反之亦然的开销所困扰?

至少你链接到的页面没有提到
货币
数据类型,并且只打开了
数值
关联


如果它是我的数据,我可能会存储一个整数的货币“单位”——便士,或十分之一便士,或百分之一便士,任何合适的——然后使用比例因子将整数输入转换为十进制,相当于从数据库读取数据时的计算。处理整数更难。

sqlite3
允许您注册适配器(插入时透明地将
小数
转换为
文本
)和转换器(提取时透明地将
文本
转换为
小数

以下是示例代码的一个稍加修改的版本:

屈服

4.12
<class 'decimal.Decimal'>
4.12

我发现我不得不对unutbu的方法做一点小小的调整。对于一个值为“4.00”的修改示例,它从数据库返回为“4”。我处理的是商品,不想将精度硬编码到数据库中(就像我只需乘以和除以100所做的那样)。因此,我对转换函数进行了如下调整:

def adapt_decimal(d):
    return '#'+str(d)

def convert_decimal(s):
    return D(s[1:])
这在美学上不是很好,但确实挫败了sqlite将字段存储为整数的渴望,并失去了对精度的跟踪。

  • 如果列的声明类型包含任何字符串 “CHAR”、“CLOB”或“TEXT”则该列具有文本相关性。通知 类型VARCHAR包含字符串“CHAR”,因此被赋值 文本亲和力
您可以将列声明为您喜欢的任何类型:

创建表a_测试( 十进制DECTEXT NOT NULL/*将存储为文本*/ );



不知道这是否是一个好的处理方法-欢迎评论

我基本上遵循与其他人相同的方法,但添加了一项。问题在于,定义适配器和转换器会处理逐行访问十进制列的情况。但是,当您发出聚合函数时,例如对所有行的十进制列求和,则使用实数(即浮点算术)进行求和,返回的结果将是浮点。在下面的示例中,我知道我存储的十进制值有两位小数(代表美国货币),因此我希望最终答案返回到两位小数。我可以在检索到浮点和之后执行此操作。但这很简单:

  • 为假定精度为两位小数的特定
    小数2
    类型指定额外的转换器
  • 使用
    sqlite3.PARSE\u COLNAMES
  • 检索需要从实数转换为十进制并四舍五入到小数点后两位的列时,请对列名使用特殊语法
  • 印刷品:

    12010.000000000178
    12010.00
    
    120100000.00
    
    3889.54
    3889.54
    
    重要提示

    这个解决方案并不完美。如果您要聚合足够多的行,则浮点近似值可能会累积,因此在将总和转换回十进制时,四舍五入到两位不足以得到正确的答案。例如,如果我们插入并汇总了10000000行:

    for _ in range(10000000):
        cursor.execute("insert into test(amount) values(?)", ("12.01",))
    conn.commit()
    
    那么,我们本来可以得到的总数将是
    120100000.02
    ,而不是希望得到的
    120100000.01
    。因此,为了绝对确保将正确的结果聚合到正确的位置数,我们必须分别读取和求和每一行:

    cursor.execute("select amount from test")
    sum = Decimal('0.00')
    for row in iter(cursor.fetchone, None):
        sum += row[0]
    print(sum)
    
    印刷品:

    12010.000000000178
    12010.00
    
    120100000.00
    
    3889.54
    3889.54
    
    但在许多情况下,我所概述的方法应该是足够的,并且肯定是对完全省略舍入的改进

    比如说。
    AVG
    函数不太可能出现与
    SUM
    函数相同程度的舍入问题,其值可能是您无论如何都想要舍入的值。在下面的示例中,我们在
    .01
    7777.77
    之间插入10000000个随机值,首先使用
    AVG
    聚合函数计算四舍五入到两位的平均值,然后将各行相加,除以行数,并将此商四舍五入到两位:

    for _ in range(10000000):
        cursor.execute("insert into test(amount) values(?)", (Decimal(randint(1, 777777)) / 100,))
    conn.commit()
    
    cursor.execute("select avg(amount) as `amount [decimal2]` from test")
    row = cursor.fetchone()
    print(row[0])
    
    cursor.execute("select amount from test")
    sum = Decimal('0.00')
    cnt = 0
    for row in iter(cursor.fetchone, None):
        sum += row[0]
        cnt += 1
    print((sum / cnt).quantize(Decimal('.01'), rounding=ROUND_HALF_UP))
    
    印刷品:

    12010.000000000178
    12010.00
    
    120100000.00
    
    3889.54
    3889.54
    

    使用您自己的数据类型并使用BLOB类型?这不是在文章中提到的吗?@William,是的,这远不是一个新想法。:)只需确保为应用程序设置足够大的缩放参数<代码>2对于小型企业来说可能足够了,但您可能需要
    3
    4
    、或
    5
    或更多,具体取决于货币换算或利率计算等。此解决方案不再有效。根据sqlite3文档,转换器函数总是以
    bytes
    格式调用,因此为了使代码在Python 3.8中工作,必须在
    convert\u decimal
    函数的定义上调用
    D(s.decode('utf-8'))