Как преобразовать десятичный Python в числовой SQLite? - PullRequest
12 голосов
/ 12 июня 2011

У меня есть программа, которая читает финансовые данные в формате JSON и вставляет их в базу данных SQLite. Проблема в том, что я вставляю его в числовой столбец SQLite, и он не похож на объект десятичный .

Я нашел этот вопрос ответил раньше , но ответ устарел, и, насколько я понимаю, SQLite теперь имеет тип данных валюты , называемый цифрой .

Прямо сейчас в качестве обходного пути я храню десятичные значения в виде текста, но возможно ли сохранить его как числовой? Я застрял на накладных расходах преобразования десятичных знаков в строки и наоборот для вставки базы данных и финансовых расчетов?

Ответы [ 4 ]

22 голосов
/ 12 июня 2011

sqlite3 позволяет зарегистрировать адаптер (для прозрачного преобразования Decimals в TEXT при вставке) и преобразователь (для прозрачного преобразования TEXT в Decimals при извлечении).

Ниже приведена слегка измененная версия примера кода из документов :

import sqlite3
import decimal
D=decimal.Decimal

def adapt_decimal(d):
    return str(d)

def convert_decimal(s):
    return D(s)

# Register the adapter
sqlite3.register_adapter(D, adapt_decimal)

# Register the converter
sqlite3.register_converter("decimal", convert_decimal)

d = D('4.12')

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(d decimal)")

cur.execute("insert into test(d) values (?)", (d,))
cur.execute("select d from test")
data=cur.fetchone()[0]
print(data)
print(type(data))

cur.close()
con.close()

выход

4.12
<class 'decimal.Decimal'>
2 голосов
/ 08 августа 2011

Я обнаружил, что мне нужно немного подправить подход Унутбу. С измененным примером со значением «4,00» он возвращается из базы данных как «4». Я имею дело с товарами и не хочу жестко закодировать точность в базе данных (как я сделал бы, если бы я просто умножил и разделил на 100). Поэтому я настроил функции преобразования следующим образом:

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

def convert_decimal(s):
    return D(s[1:])

, что не очень эстетично, но побеждает стремление sqlite сохранить поле как целое число и потерять точность.

1 голос
/ 12 июля 2012

http://www.sqlite.org/datatype3.html#affinity

  • Если объявленный тип столбца содержит какие-либо из строк "CHAR", "CLOB" или "TEXT", то этот столбец имеет сходство TEXT.Обратите внимание, что тип VARCHAR содержит строку «CHAR» и, таким образом, ему присваивается сходство TEXT.

Вы можете объявить столбцы любого типа, который вам нравится:

CREATE TABLE a_test (a_decimal DECTEXTNOT NULL / * будет храниться как TEXT * /);


def adapt_decimal(d):
    return str(d)

def convert_decimal(s):
    return decimal.Decimal(s)

# Register the adapter
sqlite3.register_adapter(decimal.Decimal, adapt_decimal)

# Register the converter
sqlite3.register_converter("DECTEXT", convert_decimal)

con = sqlite3.connect("test.s3db", detect_types=sqlite3.PARSE_DECLTYPES)
C1 = con.cursor()

C1.execute("INSERT INTO a_test VALUES(?)", (decimal.Decimal("102.20"),))

Не знаю, является ли это хорошим способом справиться с этим или нет - комментарии приветствуются

1 голос
/ 12 июня 2011

По крайней мере на странице, на которую вы ссылались, не упоминается тип данных currency, а пример типа данных decimal(10,5) просто включает сходство NUMERIC.

Если бы это были мои данные, я бы, вероятно, хранил целое число "единиц" валюты - пенни, или десятые доли копейки, или сотые доли копейки, что бы это ни было подходящим - и затем использовал бы масштабный коэффициент , чтобы преобразовать целочисленный ввод в десятичный эквивалент для вычисления при чтении данных из базы данных. Труднее облажаться с целыми числами.

...