Странное сообщение об ошибке SQLAlchemy: TypeError: объект 'dict' не поддерживает индексацию

152

Я использую созданный вручную SQL для извлечения данных из базы данных PG с помощью SqlAlchemy. Я пытаюсь выполнить запрос, который содержит SQL-подобный оператор '%' и, кажется, бросает SqlAlcjhemy через цикл:

sql = """
       SELECT DISTINCT u.name from user u
        INNER JOIN city c ON u.city_id = c.id
        WHERE c.designation=upper('fantasy') 
        AND c.id IN (select id from ref_geog where short_name LIKE '%opt')
      """

# The last line in the above statement throws the error mentioned in the title. 
# However if the last line is change to:
# AND c.id IN (select id from ref_geog where short_name = 'helloopt')
# the script runs correctly.
#
# I also tried double escaping the '%' i.e. using '%%' instead - that generated the same error as previously.

connectDb()
res = executeSql(sql)
print res
closeDbConnection()

Кто-нибудь знает, что вызывает это вводящее в заблуждение сообщение об ошибке и как я могу его исправить?

[[Редактировать]]

Прежде чем кто-либо спросит, нет ничего особенного или необычного в функциях, включенных выше. Например, функция executeSql () просто вызывает conn.execute (sql) и возвращает результаты. Переменная conn - это просто ранее установленное соединение с базой данных.

Гомункул Ретикулли
источник
вы можете разместить код executeSql(...)? А также, действительно ли вы RETURNING *в SELECTзаявлении?
фургон
@van Я пропустил это. В SQL-запросе, вызывающем проблему, нет «ВОЗВРАТА *». Исправлю вопрос.
Homunculus Reticulli
1
полезен ли этот ответ [ stackoverflow.com/questions/3944276/… ?
фургон
2
@van: Спасибо !. Да. Мне пришлось использовать '\ %%' вместо '%'. Теперь оператор выполняется правильно.
Homunculus Reticulli
3
большой. пожалуйста, опубликуйте короткий ответ (и примите его), который сработал для вас, для полноты картины.
фургон

Ответы:

244

Вы должны дать %%его использовать, %потому что %в python используется как форматирование строк, поэтому, когда вы пишете single, %предполагается, что вы собираетесь заменить какое-то значение этим.

Поэтому, если вы хотите поместить single %в строке с запросом, всегда ставьте double %.

Нилеш
источник
29
Я бы хотел, чтобы они обновили это сообщение об ошибке, каждый раз, когда я его получаю, я попадаю на эту страницу и отвечаю
oshi2016
89

SQLAlchemy имеет text() функция обертывания текста, которая, кажется, правильно избегает SQL для вас.

Т.е.

res = executeSql(sqlalchemy.text(sql))

должен работать на вас и избавить вас от необходимости выполнять экранирование вручную.

Илья Эвериля
источник
14
Это должен быть выбранный ответ. В моем случае это решило проблему.
Гани Симсек
1
Обратите внимание, что это не исключает комментариев, но в остальном это фантастическое решение.
ClimbsRocks
Это сработало для меня, и его было проще реализовать, чем изменять все наши запросы с двойным%
Филипп Огер
4

Похоже, ваша проблема может быть связана с этой ошибкой .

В этом случае вам следует сделать тройной выход в качестве обходного пути.

Брайан Кейн
источник
2

Я нашел еще один случай, когда появляется эта ошибка:

c.execute("SELECT * FROM t WHERE a = %s")

Другими словами, если вы указали параметр ( %s) в запросе, но забыли добавить параметры запроса. В этом случае сообщение об ошибке вводит в заблуждение.

Туптек
источник
1

Еще одно замечание - вы должны также экранировать (или удалять) %символы в комментариях. К сожалению, sqlalchemy.text(query_string)не обошлось и без знаков процента в комментариях.

Восхождение на скалы
источник
1

Другой способ решения вашей проблемы, если вы не хотите экранировать %символы или использовать их sqlalchemy.text(), - использовать регулярное выражение.

Вместо того:

select id from ref_geog where short_name LIKE '%opt'

Попробуйте (для соответствия с учетом регистра):

select id from ref_geog where short_name ~ 'opt$' 

или (без учета регистра):

select id from ref_geog where short_name ~* 'opt$'

Оба LIKEи регулярное выражение описаны в документации по сопоставлению с образцом .

Обратите внимание, что:

В отличие от шаблонов LIKE, регулярному выражению разрешено совпадать в любом месте строки, если только регулярное выражение явно не привязано к началу или концу строки.

Для привязки вы можете использовать утверждение $для конца строки (или ^для начала).

C8H10N4O2
источник
0

Это также может быть результатом случая - в случае, если параметры, передаваемые в SQL, объявлены в формате DICT и обрабатываются в SQL в форме LIST или TUPPLE.

Пралхад Нарсин Сонар
источник