Как можно сравнить пустое значение из базы данных?

Как я могу оптимизировать функцию вывода количества реферальных партнеров в телеграм-боте? Некоторые пользователи могут не иметь нашей реферальной ссылки в базе данных, и в этом случае должно выводиться число 0. Если у кого-то есть наша ссылка, нужно посчитать, сколько пользователей ее имеют. При этом возникает ошибка: "UnboundLocalError: local variable 'us_active' referenced before assignment". 

Вот часть кода, в которой возникает ошибка:

```python
@dp.message_handler(text=' Партнёры')
async def all_message(message: types.CallbackQuery):
    ref_active = db.cur.execute('SELECT referal_id FROM users').fetchall()
    for ref_id in ref_active:
        for row in ref_id:
            if row == message.from_user.id: # сравниваем все реферальные ссылки на нашу
                user_name = db.cur.execute('SELECT user_name FROM users WHERE referal_id = ?', (row,)).fetchall()
                if len(user_name) > 0:
                    us_active = 0 + len(user_name)
                else:
                    us_active = 0
    await bot.send_message(message.chat.id, f"✅ Активированные партнёры: {us_active} чел.\n\n Ваша пртнёрская ссылка: https://t.me/geekinvest_bot?start={message.from_user.id}", reply_markup=partners)
```
  • 30 января 2024 г. 21:38
Ответы на вопрос 2
Для сравнения пустых значений в SQL вы обычно используете оператор `IS NULL` или `IS NOT NULL`. Однако в вашем коде вы ищете конкретные значения, так что это не должно быть проблемой.

Проблема, которую вы испытываете, возникает из-за того, что переменная `us_active` объявляется внутри цикла и в блоке условия. Если условие `row == message.from_user.id` никогда не выполняется, переменная `us_active` не будет инициализирована, но вне цикла вы пытаетесь использовать её значение.

Давайте оптимизируем это и одновременно исправим ошибку. Также я заметил, что у вас может быть проблема с логикой запроса к базе данных, потому что вы получаете всех пользователей, а затем ищите среди них рефералов указанного пользователя. В вашем текущем запросе не учитывается `message.from_user.id`.

Ваш код может выглядеть примерно так:

```python
@dp.message_handler(text=' Партнёры')
async def all_message(message: types.Message):
    # Получаем количество активных рефералов для пользователя
    count_active = db.cur.execute('SELECT COUNT(*) FROM users WHERE referal_id = ?', (message.from_user.id,)).fetchone()[0]
    
    # Формируем ответное сообщение
    response_message = (
        f"✅ Активированные партнёры: {count_active} чел.\n\n"
        f"Ваша пртнёрская ссылка: https://t.me/geekinvest_bot?start={message.from_user.id}"
    )
    # Отправляем сообщение
    await bot.send_message(message.chat.id, response_message, reply_markup=partners)

```

Вот несколько ключевых моментов оптимизации и исправления:

1. Переменная `us_active` больше не нужна, так как теперь запрос к базе данных сразу возвращает количество активных рефералов. Мы делаем это путем подсчета записей в таблице `users`, где `referal_id` равен `message.from_user.id`.

2. Мы используем `COUNT(*)` для подсчета количества записей, что избавляет от необходимости сначала получать все записи, а потом считать их.

3. `fetchone()[0]` используется для получения первого значения из первой строки результата, что является общим количеством подходящих записей.

4. Параметризованный запрос более безопасен и предотвращает SQL-инъекции.

5. Я поменял тип `message` с `types.CallbackQuery` на `types.Message`. Насколько я понимаю из контекста, эта функция обрабатывает текстовые сообщения, а не колбэк-запросы от инлайновой клавиатуры.

Убедитесь, что переменная `partners` генерируется корректно и что экземпляр `db.cur` (курсор базы данных) правильно настроен и используется.
Учи матчасть. Всё делается одним запросом. 
Группировка сделает так, что для каждого referal_id будет выведена одна строка, а групповые функции посчитают некий итог для каждой группы строк с одним и тем же значением referal_id. В частности, COUNT() посчитает сколько строк в группе.
Похожие вопросы