Почему SQLite преобразует строку в число и как это исправить
При импорте данных из CSV в SQLite многие разработчики сталкиваются с ситуацией, когда числовой артикул (например, 777777) записывается в базу как 777777.0, хотя поле объявлено как TEXT. Проблема кроется в особенностях работы библиотеки pandas и драйвера SQLite. В этой статье разберём, как заставить SQLite сохранять строковые значения без автоматического преобразования.
Причина появления .0 в строковом поле
SQLite использует динамическую типизацию - тип значения определяется не столько объявлением столбца, сколько самим переданным значением. Если вы передаёте число с плавающей точкой (float), SQLite может сохранить его как REAL, даже если столбец объявлен как TEXT. В вашем коде pandas.read_csv автоматически определяет тип данных. Если в CSV артикул состоит только из цифр, pandas присваивает столбцу тип int64 или float64, и при вставке через str(row['Артикул']) число сначала преобразуется в строку, но уже с десятичной точкой, если тип был float.
Как исправить: гарантированное сохранение строки
Есть несколько способов принудительно сохранить артикул как строку без лишних символов.
Способ 1: Явное указание типа при чтении CSV
Самый надёжный вариант - задать тип столбца Артикул как строку сразу при загрузке CSV. Это предотвращает автоматическое преобразование pandas.
import pandas as pd
dtype_dict = {'Артикул': str}
df = pd.read_csv('products.csv', dtype=dtype_dict)
# Теперь row['Артикул'] уже строка, даже если в CSV число
sku = row['Артикул'] # '777777', а не 777777.0Способ 2: Очистка строки перед вставкой
Если вы не можете контролировать тип при чтении, преобразуйте значение в строку и удалите лишние символы.
sku = str(row['Артикул']).split('.')[0] # обрезает '.0'
# Или более универсально:
sku = str(int(float(row['Артикул']))) if str(row['Артикул']).replace('.', '', 1).isdigit() else str(row['Артикул'])Способ 3: Использование параметра converters в pandas
Можно применить функцию-конвертер для конкретного столбца.
def clean_sku(value):
try:
# Если значение - число, преобразуем в int, потом в строку
return str(int(float(value)))
except:
return str(value)
df = pd.read_csv('products.csv', converters={'Артикул': clean_sku})Проверка типа в SQLite
После исправления убедитесь, что данные сохранились корректно. Выполните запрос:
SELECT sku, typeof(sku) FROM products WHERE id = 123;Если в результате typeof возвращает text, а значение - '777777' без точки, проблема решена.
Частые ошибки при импорте CSV в SQLite
- Пропуск заголовков: Убедитесь, что в CSV есть строка с названиями столбцов, и они совпадают с теми, что вы используете в коде (например, 'Артикул', а не 'SKU').
- NaN значения: Если в столбце артикула есть пустые ячейки, pandas преобразует их в NaN. В вашем коде уже есть проверка
np.isnan(row['ID']), но аналогично нужно обрабатывать и артикул. - Пробелы в данных: Иногда в CSV артикулы содержат невидимые пробелы. Используйте
str(row['Артикул']).strip().
Заключение
Проблема с появлением .0 в строковых полях SQLite решается на этапе чтения CSV. Самый простой способ - задать тип столбца как str через параметр dtype в pandas или использовать конвертер для очистки данных. После этого SQLite будет корректно сохранять артикулы как текст без автоматического преобразования в число.