Сообщение об ошибке Strange SQLAlchemy: TypeError: объект 'dict' не поддерживает индексирование
Я использую ручной 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()
Кто-нибудь знает, что вызывает это вводящее в заблуждение сообщение об ошибке, и как я могу его исправить?
[[Edit]]
Прежде чем кто-либо спросит, нет ничего особенного или не интересует функции, включенные выше. Например, функция executeSql() просто вызывает conn.execute(sql) и возвращает результаты. Переменная conn - это просто ранее установленное соединение с базой данных.
Ответы
Ответ 1
Вы должны дать %%
использовать его как %
, потому что %
в python используется как форматирование строки, поэтому, когда вы пишете одиночный %
, предполагается, что вы собираетесь заменить какое-то значение этим.
Поэтому, когда вы хотите разместить одиночный %
в строке с запросом, всегда используйте double %
.
Ответ 2
В SQLAlchemy есть функция text()
для переноса текста, которая, по-видимому, корректно экранирует SQL для вас.
Т.е.
res = executeSql(sqlalchemy.text(sql))
должен работать для вас и избавить вас от необходимости выполнять ручное экранирование.
Ответ 3
Похоже, что ваша проблема может быть связана с этой ошибкой.
В этом случае, вы должны тройной побег в качестве обходного пути.
Ответ 4
Я обнаружил еще один случай, когда появляется эта ошибка:
c.execute("SELECT * FROM t WHERE a = %s")
Другими словами, если вы задаете параметр (%s
) в запросе, но вы забудете добавить параметры запроса. В этом случае сообщение об ошибке очень вводит в заблуждение.
Ответ 5
Я не могу найти "executeSql" в документах sqlalchemy версии 1.2, но у меня сработала следующая строка
engine.execute(sqlalchemy.text(sql_query))
Ответ 6
Еще одно примечание - вы должны избегать (или удалять) %
символов в комментариях. К сожалению, sqlalchemy.text(query_string)
не пропускает процентные знаки в комментариях.
Ответ 7
Это также может быть вызвано случаем - в случае, если параметры, передаваемые на SQL, объявляются в формировании DICT и обрабатываются в SQL в виде LIST или TUPPLE.
Ответ 8
Другой способ решить вашу проблему, если вы не хотите экранировать символы %
или использовать 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
и regex описаны в документации по сопоставлению с образцом.
Обратите внимание, что:
В отличие от шаблонов LIKE, регулярному выражению разрешено совпадать в любом месте строки, если только регулярное выражение явно не привязано к началу или концу строки.
Для привязки вы можете использовать утверждение $
для конца строки (или ^
для начала).