Почему 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 будет корректно сохранять артикулы как текст без автоматического преобразования в число.

    Часто задаваемые вопросы