Дивне повідомлення про помилку SQLAlchemy: TypeError: 'dict' об'єкт не підтримує індексацію


145

Я використовую вручну створений 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
чудовий. будь ласка, опублікуйте коротку відповідь (і прийміть її), яка працювала для вас заради повноти.
ван

Відповіді:


227

Ви повинні дати %%йому використовувати його так, %тому що %в python використовується як форматування рядків, тому коли ви пишете сингл, %припускайте, що ви збираєтесь замінити якесь значення цим.

Тому коли ви хочете розмістити одинарний %рядок із запитом, завжди розмістіть подвійний %.


27
Я б хотів, щоб вони оновлювали це повідомлення про помилку, кожного разу, коли я отримую це, я закінчую посадку на цій сторінці і відповідаю
oshi2016

86

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

Тобто

res = executeSql(sqlalchemy.text(sql))

повинен працювати для вас і врятувати вас від необхідності виконувати втечу вручну.


13
Це має бути обрана відповідь. Це вирішило питання в моєму випадку.
Гані Сімсек

1
Зауважте, що це не уникає коментарів, але в іншому випадку це фантастичне рішення.
ClimbsRocks

Це працювало для мене і було легше реалізувати, ніж змінювати всі наші запити з подвійним%
Philippe Oger



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 у вигляді СПИСОК або TUPPLE.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.