Странное сообщение об ошибке 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

Это сработало для меня, и его было проще реализовать, чем изменять все наши запросы с двойным%
Филипп Огер



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

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


0

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.