Как подставить значение в запрос sqlite?
Здравствуйте, столкнулся с проблемой невозможности подставить значение в сам sql запрос используя '?'. Приведу похожий код ради наглядности:
#нерабочий код result = cur.execute('SELECT ? FROM messages ORDER BY id DESC LIMIT 1', (value,)).fetchone() #value = 'message_time ' #рабочий код result = cur.execute('SELECT message_time FROM messages ORDER BY id DESC LIMIT 1').fetchone() |
#нерабочий код result = cur.execute('SELECT ? FROM messages ORDER BY id DESC LIMIT 1', (value,)).fetchone() #value = 'message_time ' #рабочий код result = cur.execute('SELECT message_time FROM messages ORDER BY id DESC LIMIT 1').fetchone()
Ошибка при попытке конвертировать в int:
ValueError: invalid literal for int() with base 10: 'message_time'
Дополнительно:
Имена полей подставлять нельзя.
- Можете пожалуйста предложить решение с подставлением, в контексте моей программы это достаточно важно
- Uadfl, изменить свой подход к структуре таблиц. Поля как правило не должны подставляться динамически, при запросе уже известно, какое поле за что отвечает. А что конкретно изменить, не известно, пока не опишете, для чего вам понадобилось динамически выбирать поля, зачем вообще так решили сделать.
- o5a, если коротко, то есть функция, которая должна возвращать значение из передаваемого ей столбца
- Uadfl, а зачем нужна такая функция?
Это действительно не очень хорошее решение в большинстве ситуаций. -
функция, которая должна возвращать значение из передаваемого ей столбца
Получай всю запись, все поля, а на стороне клиента выбирай оттуда только нужное поле.
- Akina, не надо советовать такие плохие решения... особенно если там таблица с сотнями полей или блобами в них на мегабайты.
- rPman, крайне мало фреймворков позволяет динамически подставлять имена объектов. Так что альтернативой будет разве что монстрообразный (для таблицы с сотнями полей) CASE.
- rPman, ну, блобы - штука относительно редкая, а в остальном это лучше, чем сборка строки запроса.
- Сергей Горностаев, нужно понимать, почему именно считается плохим тоном генерация sql запроса вместо параметризованных и если ни одна из причин не попадает под задачи автора, то почему нет.
не нужно решать вымышленные проблемы, создавая новые.
p.s. у sqlite prepared statements не увеличивают производительность (либо это на уровне погрешности), т.е. единственный их бонус - защита от sql иньекций и просто красота кода, не вынуждающая разработчика делать экранирование строк.
- rPman, прежде всего это идиоматичность. Использование реляционной базы данных подразумевает жёсткую схему БД определённую до рантайма. В очень редких случаях требуется работать в рантайме не с данными, а со схемой, чаще это сигнал плохой архитектуры.
- Сергей Горностаев, у меня был проект, где пользователь подсовывал свою базу данных (проект древней гис, там шейпы и таблицы), нужно было проанализировать ее структуру, содержимое таблиц и предлагать для выбора таблицы и поля, указывая их назначение, дальше приложение конвертировало эти данные (по факту копирование указанных полей с вариантом объединения таблиц в одну или разделение и выявление справочников).
Извини, в такой задаче принципиально невозможно заранее подготовить запросы, да и нет в этом смысла.
так как автор так и не удосужился задачу свою описать, приходится догадываться и предлагать самые невероятные примеры
- rPman, я и говорю, редкий случай.
- Uadfl, опять же, Вы озвучили свой способ решения, который как тут уже объяснили, выглядит сомнительно в приложении к реляционным БД. А хотелось бы увидеть, зачем изначально вам такое потребовалось, динамически подставлять названия полей.
Выглядит как очередная Проблема_XYЕсли простыми словами, это как если бы обратились с вопросом:
- Как мне укрепить микроскоп, а то он быстро выходит из строя
- *пожав плечами, предлагают решения по укреплению конструкции микроскопа*
А на самом деле выясняется, что автор вопроса использовал микроскоп, чтобы забивать гвозди, и правильным ответом на подобный вопрос было бы "использовать молоток", а не пытаться укрепить микроскоп. - o5a, ну я понял, спасибо
- Uadfl, прямым ответом на ваш вопрос будет использовать форматирование строк, например через f-строки, как предложил ниже wincrx, потому что параметризированые запросы (механизм через '?') для подстановки названий идентификаторов в принципе не работает, там только форматировать строку запроса. Просто это в целом не особо правильно делать, и может быть даже опасно, если вы эти названия полей будете не сами жестко контролировать, а брать из ввода пользователя.
Но если бы объяснили, зачем решили так динамически выбирать названия полей, вам тут могли бы подсказать, как сделать правильно.
Ответы:
Почему ты f-строку не используешь?
result = cur.execute(f'SELECT {value} FROM messages ORDER BY id DESC LIMIT 1').fetchone() |
result = cur.execute(f'SELECT {value} FROM messages ORDER BY id DESC LIMIT 1').fetchone()
- Может по этому?
Почему не стоит использовать f строки в SQL Python запросах? - Михаил Р., в данном случае, особенно если проверять предварительно строчку на ее формат и допустимые названия полей, это нормальное решение для поставленной задачи.
другой вопрос что задача поставлена возможно чуть чуть некорректно, но в любом случае такое случается (например если пишешь приложение, работающее с чужими базами данных случайной структуры, да в этом случае тоже можно делать prepared выражения под соответствующую структуру в момент выбора базы, но смысла в этом уже не так много)
Коробочное решение этой задачи называется SQL-Builder.
Вот пример такого https://pypika.readthedocs.io/en/latest/2_tutorial...
Использовать string interpolation здесь технически возможно, но не выдерживает критики
по инфо-безопасности. Атака на инжекцию - это Top 10 уязвимостей софта в 21 веке.
Вот об этом коллеги тоже пишут в ответах.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для подстановки значений в запрос SQLite можно использовать параметризированные запросы, чтобы избежать уязвимостей безопасности и предотвратить SQL-инъекции.
Пример параметризированного запроса в PHP:
$db = new SQLite3('database.db'); $stmt = $db->prepare('SELECT * FROM table WHERE column = :value'); $stmt->bindValue(':value', $value, SQLITE3_TEXT); $result = $stmt->execute();
В этом примере мы подготавливаем запрос с помощью метода `prepare()` и затем подставляем значение с помощью метода `bindValue()`. Второй аргумент `SQLITE3_TEXT` указывает на тип данных, который мы ожидаем, но его можно изменить в зависимости от типа данных, который вы хотите использовать.
Если вы работаете с другим языком программирования, то подход будет аналогичным. Главное, чтобы ваш API для работы с SQLite поддерживал параметризированные запросы.
Использование параметризированных запросов не только обеспечивает безопасность вашего приложения, но также повышает производительность за счет кэширования запросов в SQLite.