Message d'erreur étrange SQLAlchemy: TypeError: l'objet 'dict' ne prend pas en charge l'indexation


145

J'utilise SQL fabriqué à la main pour récupérer des données à partir d'une base de données PG, en utilisant SqlAlchemy. J'essaie une requête qui contient le SQL comme l'opérateur '%' et qui semble lancer SqlAlcjhemy à travers une boucle:

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

Quelqu'un sait ce qui cause ce message d'erreur trompeur et comment je peux le réparer?

[[Éditer]]

Avant que quiconque ne demande, il n'y a rien de spécial ou de fantaisie dans les fonctions incluses ci-dessus. Par exemple, la fonction executeSql () appelle simplement conn.execute (sql) et renvoie les résultats. La variable conn est simplement la connexion précédemment établie à la base de données.


pouvez-vous poster le code de executeSql(...)? Et aussi, avez-vous vraiment RETURNING *dans la SELECTdéclaration?
van

@van j'ai raté celui-là. Il n'y a pas de «RETURNING *» dans le SQL qui cause le problème. Je vais corriger la question.
Homunculus Reticulli


2
@van: Merci !. Oui. J'ai dû utiliser '\ %%' au lieu de '%'. L'instruction est maintenant correctement exécutée.
Homunculus Reticulli

3
génial. veuillez poster une réponse courte (et l'accepter) qui a fonctionné pour vous par souci d'exhaustivité.
van

Réponses:


228

Vous devez donner %%pour l'utiliser %car %en python est utilisé comme formatage de chaîne, donc lorsque vous écrivez un single, %il suppose que vous allez remplacer une valeur par ceci.

Ainsi, lorsque vous souhaitez placer un simple %dans une chaîne avec une requête, placez toujours le double %.


27
Je souhaite qu'ils mettent à jour ce message d'erreur, chaque fois que je l'obtiens, je
finis

86

SQLAlchemy a une text()fonction pour envelopper le texte qui semble échapper correctement au SQL pour vous.

C'est à dire

res = executeSql(sqlalchemy.text(sql))

devrait fonctionner pour vous et vous éviter d'avoir à faire l'échappement manuel.


13
Cela devrait être la réponse choisie. Cela a résolu le problème dans mon cas.
Gani Simsek

1
Notez que cela n'échappe pas aux commentaires, mais sinon, c'est une solution fantastique.
ClimbsRocks

Cela a fonctionné pour moi et était plus facile à mettre en œuvre que de modifier toutes nos requêtes avec un double%
Philippe Oger

6

Je ne trouve pas le "executeSql" dans la documentation de sqlalchemy version 1.2 , mais la ligne ci-dessous a fonctionné pour moi

engine.execute(sqlalchemy.text(sql_query))

4

Il semble que votre problème soit lié à ce bogue .

Dans ce cas, vous devez triple-échapper pour contourner le problème.


2

J'ai trouvé un autre cas lorsque cette erreur apparaît:

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

En d'autres termes, si vous fournissez le paramètre ( %s) dans la requête, mais que vous oubliez d'ajouter des paramètres de requête. Dans ce cas, le message d'erreur est très trompeur.


1

Une dernière remarque: vous devez également échapper (ou supprimer) des %caractères dans les commentaires. Malheureusement, sqlalchemy.text(query_string)n'échappe pas aux signes de pourcentage dans les commentaires.


1

Une autre façon de résoudre votre problème, si vous ne voulez pas échapper %ou utiliser des caractères sqlalchemy.text(), est d'utiliser une expression régulière.

Au lieu de:

select id from ref_geog where short_name LIKE '%opt'

Essayez (pour une correspondance sensible à la casse):

select id from ref_geog where short_name ~ 'opt$' 

ou (pour insensible à la casse):

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

Les deux LIKEet regex sont traités dans la documentation sur la correspondance de modèles .

Notez que:

Contrairement aux modèles LIKE, une expression régulière est autorisée à correspondre n'importe où dans une chaîne, sauf si l'expression régulière est explicitement ancrée au début ou à la fin de la chaîne.

Pour une ancre, vous pouvez utiliser l'assertion $pour la fin de la chaîne (ou ^pour le début).


0

Cela pourrait également résulter du cas - dans le cas où les paramètres à passer au SQL sont déclarés au format DICT et sont manipulés dans le SQL sous la forme de LISTE ou TUPPLE.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.