Dziwny komunikat o błędzie SQLAlchemy: TypeError: obiekt „dict” nie obsługuje indeksowania

145

Używam ręcznie spreparowanego języka SQL do pobierania danych z bazy danych PG przy użyciu SqlAlchemy. Próbuję zapytać, które zawiera operator podobny do SQL „%” i wydaje się, że SqlAlcjhemy przechodzi przez pętlę:

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()

Czy ktoś wie, co powoduje ten mylący komunikat o błędzie i jak mogę to naprawić?

[[Edytować]]

Zanim ktoś zapyta, nie ma nic specjalnego ani wyszukanego w funkcjach opisanych powyżej. Na przykład funkcja executeSql () po prostu wywołuje conn.execute (sql) i zwraca wyniki. Zmienna conn to po prostu wcześniej nawiązane połączenie z bazą danych.

Homunculus Reticulli
źródło
czy możesz wysłać kod executeSql(...)? A także, czy naprawdę masz to RETURNING *w SELECToświadczeniu?
van
@van Brakowało mi tego. W kodzie SQL, który powoduje problem, nie ma napisu „RETURNING *”. Poprawię pytanie.
Homunculus Reticulli
1
czy ta odpowiedź [ stackoverflow.com/questions/3944276/… jest pomocna?
van
2
@van: Dzięki !. tak. Musiałem użyć „\ %%” zamiast „%”. Instrukcja jest teraz poprawnie wykonana.
Homunculus Reticulli
3
świetny. prześlij krótką odpowiedź (i zaakceptuj ją), która zadziałała dla Ciebie ze względu na kompletność.
van

Odpowiedzi:

227

Musisz dać, %%aby go używać, %ponieważ %w pythonie jest używane jako formatowanie ciągów, więc kiedy piszesz single, %zakłada się, że zamierzasz zastąpić jakąś wartość tą wartością.

Więc jeśli chcesz umieścić pojedynczy %w ciągu za pomocą zapytania, zawsze umieszczaj double %.

Nilesh
źródło
27
Chciałbym, żeby zaktualizowali ten komunikat o błędzie, za każdym razem, gdy go dostaję, ląduję na tej stronie i odpowiadam
oshi2016
86

SQLAlchemy ma text()funkcję zawijania tekstu, która wydaje się prawidłowo uciec przed SQL.

To znaczy

res = executeSql(sqlalchemy.text(sql))

powinien zadziałać dla Ciebie i uchronić Cię przed koniecznością wykonywania ręcznej ucieczki.

Ilja Everilä
źródło
13
To powinna być wybrana odpowiedź. To rozwiązało problem w moim przypadku.
Gani Simsek,
1
Zauważ, że to nie uniknie komentarzy, ale poza tym jest fantastycznym rozwiązaniem.
ClimbsRocks
To zadziałało dla mnie i było łatwiejsze do zaimplementowania niż zmiana wszystkich naszych zapytań z podwójnym%
Philippe Oger
6

Nie mogę znaleźć "executeSql" w dokumentacji sqlalchemy w wersji 1.2 , ale poniższa linia działała dla mnie

engine.execute(sqlalchemy.text(sql_query))
Chandra Prakash Dixit
źródło
4

Wygląda na to, że Twój problem może być związany z tym błędem .

W takim przypadku należy użyć potrójnej zmiany znaczenia jako obejścia.

Brian Cain
źródło
2

Znalazłem jeszcze jeden przypadek, gdy pojawia się ten błąd:

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

Innymi słowy, jeśli podasz parametr ( %s) w zapytaniu, ale zapomnisz dodać parametry zapytania. W tym przypadku komunikat o błędzie jest bardzo mylący.

Tupteq
źródło
1

Jeszcze jedna uwaga - musisz też uciec (lub usunąć) %znaki w komentarzach. Niestety sqlalchemy.text(query_string)nie umknie znakom procentu w komentarzach.

Wspina się po skałach
źródło
1

Innym sposobem rozwiązania problemu, jeśli nie chcesz zmieniać znaczenia %znaków lub ich używać sqlalchemy.text(), jest użycie wyrażenia regularnego.

Zamiast:

select id from ref_geog where short_name LIKE '%opt'

Spróbuj (dla dopasowania z rozróżnianiem wielkości liter):

select id from ref_geog where short_name ~ 'opt$' 

lub (bez rozróżniania wielkości liter):

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

LIKEW dokumentacji dotyczącej dopasowywania wzorców omówiono zarówno wyrażenia regularne, jak i wyrażenia regularne .

Zauważ, że:

W przeciwieństwie do wzorców LIKE, wyrażenie regularne może być dopasowane w dowolnym miejscu w ciągu, chyba że jest ono jawnie zakotwiczone na początku lub na końcu ciągu.

W przypadku kotwicy możesz użyć potwierdzenia $na końcu łańcucha (lub ^na początku).

C8H10N4O2
źródło
0

Może to również wynikać z przypadku - w przypadku, gdy parametry, które mają być przekazane do SQL, są zadeklarowane w formacie DICT i są przetwarzane w SQL w postaci LISTY lub TUPPLE.

Sonar Pralhad Narsinh
źródło