web-dev-qa-db-fra.com

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

J'utilise SQL à la main pour récupérer les données d'une base de données PG, à l'aide de SqlAlchemy. J'essaye 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 le corriger?

[[Modifier]]

Avant que quiconque ne pose la question, les fonctions décrites ci-dessus n’ont rien de spécial ou d’impressionnant. 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.

85

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

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

145
Nilesh

SQLAlchemy a une fonction text() pour le retour à la ligne qui semble échapper correctement à la requête SQL. 

C'est à dire.

res = executeSql(sqlalchemy.text(sql))

devrait travailler pour vous et vous éviter de faire l'échappement manuel.

50
user795753

Il semble que votre problème puisse être lié à ce bogue .

Dans ce cas, vous devriez échapper trois fois à une solution de contournement.

5
Brian Cain

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

engine.execute(sqlalchemy.text(sql_query))
2

Encore une note - vous devez également échapper (ou supprimer) les caractères % dans les commentaires. Malheureusement, sqlalchemy.text(query_string) n'échappe pas aux signes de pourcentage dans les commentaires. 

1
ClimbsRocks

J'ai trouvé un cas de plus 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
Tupteq

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

Au lieu de:

select id from ref_geog where short_name LIKE '%opt'

Essayez (pour la correspondance sensible à la casse):

select id from ref_geog where short_name ~ 'opt$' 

ou (pour la casse):

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

LIKE et regex sont tous deux couverts par documentation sur les correspondances de motifs .

Notez que:

Contrairement aux modèles LIKE, une expression régulière peut correspondre n'importe où dans une chaîne, à moins que l'expression régulière soit 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 chaîne (ou ^ pour le début).

0
C8H10N4O2

Cela peut également résulter du cas où les paramètres à transmettre au SQL sont déclarés dans le formate DICT et sont manipulés dans le SQL sous la forme de LIST ou TUPPLE.

0