Задать вопрос
@Vladovay

Почему данные в БД SQlite добавляются в новую строку?

Новичек в питоне, пишу бота в тг. Мне нужно получить имя, фамилию и другие данные от пользователя. Но все кроме имени и фамилии не добавляются. Либо добавляются в новую либо нет. Добавляются если в значениях id и username не стоит NOT NULL, это понятно. Как сделать чтобы они добавлялись в существующую строку? Сразу скажу что Update как пишут не помогает, но если у вас есть варианты с update, то напишите пожайлуста.

Вот код

sync def add_tg(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    username = message.from_user.username
    usertg = message.text.strip()
    async with aiosqlite.connect('base.db') as db:
        await db.execute('INSERT OR IGNORE INTO user (id, username, user_tg) VALUES(?, ?, ?)', (user_id, username, usertg))
        await db.commit()

    await message.answer(text="Введите имя")
    await state.set_state(Form.name)



@start_router.message(Form.name)
async def add_name(message: types.Message):
    user_id = message.from_user.id
    username = message.from_user.username
    usertg = message.text.strip()
    name = message.text.strip()
    try:
        async with aiosqlite.connect('base.db') as db:
            await db.execute('INSERT INTO user (id, username, user_tg, name) VALUES(?, ?, ?, ?)', (user_id, username, usertg, name))
            await db.commit()
        await message.answer("Готово")
    except Exception as e:
        await message.answer(f"Произошла ошибка {e}")


И в настоящее время есть ошибка: UNIQUE constraint failed: user.id
UNIQUE у id убирал, и снова добавлял, но она осталась.
  • Вопрос задан
  • 103 просмотра
Подписаться 1 Простой 2 комментария
Решения вопроса 3
Vindicar
@Vindicar
RTFM!
Потому что ты выполняешь два запроса INSERT. Запрос INSERT добавляет новую строку. Всё логично.
Тебе нужно сделать одно из двух:
Вариант 1. Изменить код так, чтобы бот накапливал сведения в памяти, и только на самом последнем этапе заносить собранное в БД. Я вижу, ты используешь FSM - отлично! Этот механизм позволяет хранить произвольные данные в контексте состояния.
Вариант 2. Сделать, как сделал Pasha выше - вносишь первую порцию данных через INSERT, остальные - через UPDATE. Тогда у тебя на последующих этапах будут обновляться существующая строка.
Можно сделать, как предложил fenrir - использовать UPSERT, который сводится к "если строки нет, делай INSERT, если есть, делай UPDATE", но я бы не советовал его тут использовать - лучше сначала чётко разобраться, что и как работает.

Разница между вариантами будет в ситуации, когда бот отвалился в процессе регистрации. В первом случае собранные частичные данные будут забыты, и пользователю придётся регаться с начала. Во втором случае у тебя в базе будет недореганный пользователь, что может "всплыть" (спровоцировать ошибки) в дальнейшем. Так что я бы предпочёл вариант 1.

В любом случае, поддерживаю замечание насчёт первичного ключа - это основное понятие! Пойми, что это такое, и задай его для своей таблицы.
Ответ написан
fenrir1121
@fenrir1121
Начни с документации
Вам нужна команда INSERT INTO ... ON CONFLICT ... DO UPDATE SET ... или более актуальная UPSERT.

В доках подробно дано описание и примеры использования.
Ответ написан
suprunchuk
@suprunchuk
@start_router.message(Form.tg)
async def add_tg(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    username = message.from_user.username
    usertg = message.text.strip()
    async with aiosqlite.connect('base.db') as db:
        await db.execute('''
            INSERT INTO user (id, username, user_tg) 
            VALUES(?, ?, ?) 
            ON CONFLICT(id) DO UPDATE SET 
            username=?, user_tg=?
        ''', (user_id, username, usertg, username, usertg))
        await db.commit()

    await message.answer(text="Введите имя")
    await state.set_state(Form.name)

@start_router.message(Form.name)
async def add_name(message: types.Message):
    user_id = message.from_user.id
    name = message.text.strip()
    async with aiosqlite.connect('base.db') as db:
        await db.execute('''
            UPDATE user 
            SET name = ? 
            WHERE id = ?
        ''', (name, user_id))
        await db.commit()
    await message.answer("Готово")


ну и таблица скорее всего вот так должна создаваться у вас:
CREATE TABLE IF NOT EXISTS user (
    id INTEGER PRIMARY KEY,
    username TEXT,
    user_tg TEXT,
    name TEXT
);
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы