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.


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 %.


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.


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


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.


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.


1

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


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


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.