Mensaje de error extraño de SQLAlchemy: TypeError: el objeto 'dict' no admite la indexación

145

Estoy usando SQL hecho a mano para obtener datos de una base de datos PG, usando SqlAlchemy. Estoy intentando una consulta que contiene el operador similar a SQL '%' y que parece arrojar SqlAlcjhemy a través de un bucle:

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

¿Alguien sabe qué está causando este mensaje de error engañoso y cómo puedo solucionarlo?

[[Editar]]

Antes de que alguien pregunte, no hay nada especial o elegante sobre las funciones incluidas anteriormente. Por ejemplo, la función executeSql () simplemente invoca conn.execute (sql) y devuelve los resultados. La variable conn es simplemente la conexión previamente establecida a la base de datos.

Homunculus Reticulli
fuente
¿Puedes publicar el código de executeSql(...)? Y también, ¿realmente tienes RETURNING *en la SELECTdeclaración?
van
@van me perdí esa. No hay 'RETURNING *' en el SQL que está causando el problema. Corregiré la pregunta.
Homunculus Reticulli
1
¿Es útil esta respuesta [ stackoverflow.com/questions/3944276/… ?
van
2
@van: ¡Gracias! si lo hace Tuve que usar '\ %%' en lugar de '%'. La declaración se ejecuta correctamente ahora.
Homunculus Reticulli
3
Excelente. publique una respuesta breve (y acéptela) que funcionó para usted en aras de la exhaustividad.
van

Respuestas:

227

Tienes que dar %%para usarlo %porque %en python se usa como formato de cadena, por lo que cuando escribes solo se %supone que vas a reemplazar algún valor con esto.

Entonces, cuando desee colocar single %en una cadena con consulta, coloque double %.

Nilesh
fuente
27
Desearía que hubieran actualizado ese mensaje de error, cada vez que lo recibo termino aterrizando en esta página y respondo
oshi2016
86

SQLAlchemy tiene una text()función para ajustar el texto que parece escapar correctamente del SQL por usted.

Es decir

res = executeSql(sqlalchemy.text(sql))

debería funcionar para usted y evitar que tenga que hacer el escape manual.

Ilja Everilä
fuente
13
Esta debería ser la respuesta seleccionada. Resolvió el problema en mi caso.
Gani Simsek
1
Tenga en cuenta que esto no escapa a los comentarios, sino que es una solución fantástica.
ClimbsRocks
Eso funcionó para mí y fue más fácil de implementar que cambiar todas nuestras consultas con un doble%
Philippe Oger
6

No puedo encontrar el "executeSql" en los documentos de la versión 1.2 de sqlalchemy , pero la línea siguiente funcionó para mí

engine.execute(sqlalchemy.text(sql_query))
Chandra Prakash Dixit
fuente
4

Parece que su problema puede estar relacionado con este error .

En cuyo caso, debe escapar tres veces como solución alternativa.

Brian Cain
fuente
2

Encontré un caso más cuando aparece este error:

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

En otras palabras, si proporciona el parámetro ( %s) en la consulta, pero olvida agregar parámetros de consulta. En este caso, el mensaje de error es muy engañoso.

Tupteq
fuente
1

Una nota más: también debe escapar (o eliminar) %caracteres en los comentarios. Lamentablemente, sqlalchemy.text(query_string)no escapa a los signos de porcentaje en los comentarios.

SubidasRocas
fuente
1

Otra forma de resolver su problema, si no quiere escapar de los %caracteres o usarlos sqlalchemy.text(), es usar una expresión regular.

En vez de:

select id from ref_geog where short_name LIKE '%opt'

Prueba (para coincidencias entre mayúsculas y minúsculas):

select id from ref_geog where short_name ~ 'opt$' 

o (para mayúsculas y minúsculas):

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

Ambos LIKEy regex están cubiertos en la documentación sobre coincidencia de patrones .

Tenga en cuenta que:

A diferencia de los patrones LIKE, una expresión regular puede coincidir en cualquier lugar dentro de una cadena, a menos que la expresión regular esté anclada explícitamente al principio o al final de la cadena.

Para un ancla, puede usar la aserción $para el final de la cadena (o ^para comenzar).

C8H10N4O2
fuente
0

Esto también podría resultar del caso: en caso de que los parámetros que se pasan al SQL se declaren en formato DICT y se manipulen en el SQL en forma de LIST o TUPPLE.

Sonda Pralhad Narsinh
fuente