2012-06-25 11 views
6

Estoy tratando de crear una declaración de la siguiente manera:Cómo cadena de formato cláusula IN de SQL con Python

SELECT * FROM table WHERE provider IN ('provider1', 'provider2', ...) 

Sin embargo, estoy teniendo algunos problemas con el formato de cadenas de ella desde la API de Django. Esto es lo que tengo hasta ahora:

profile = request.user.get_profile() 
providers = profile.provider.values_list('provider', flat=True) # [u'provider1', u'provider2'] 
providers = tuple[str(item) for item in providers] # ('provider1', 'provider2') 

SQL = "SELECT * FROM table WHERE provider IN %s" 
args = (providers,) 
cursor.execute(sql,args) 

DatabaseError 
(1241, 'Operand should contain 1 column(s)') 
+4

curioso. ¿Por qué estás haciendo una consulta sql 'IN' cuando ya tienes el django ORM? – jdi

+0

@jdi Es una larga consulta SQL que estoy construyendo con concatenación de cadenas basada en algunos valores ingresados ​​por el usuario (aproximadamente 20 líneas de longitud). – David542

+0

Sin embargo, el ORM tiene agregaciones. Pero supongo que tengo que decirles que el ORM no puede hacerlo :-) – jdi

Respuesta

4

MySQLdb tiene un método para ayudar con esto:

Doc

string_literal (...) string_literal (obj) - convierte objeto obj en un literal de cadena SQL. Esto significa que se han escapado todos los caracteres especiales de SQL, y está incluido entre comillas simples. En otras palabras, se lleva a cabo:

"'%s'" % escape_string(str(obj)) 

Use connection.string_literal(obj), if you use it at all. 
_mysql.string_literal(obj) cannot handle character sets. 

Uso

# connection: <_mysql.connection open to 'localhost' at 1008b2420> 

str_value = connection.string_literal(tuple(provider)) 
# '(\'provider1\', \'provider2\')' 

SQL = "SELECT * FROM table WHERE provider IN %s" 
args = (str_value,) 
cursor.execute(sql,args) 
+0

eso es genial.No sabía sobre el método string_literal. Supongo que, dado que MySQLdb sigue estrictamente la apéndice db, esto existe en la mayoría de las implementaciones (sqlite3, postgres, etc.) Definitivamente volviendo a los documentos –

+0

@ Justin.Wood: para ser sincero, realmente no lo sabía. tampoco, pero no tengo mucha experiencia previa al usar MySQLdb y pasar valores de tupla. Siempre es un ORM Acabo de mirar los documentos también para este :-) – jdi

+0

aseado. Trabajo en una base de código heredada que no usa un ORM, y obtenemos este tipo de cosas constantemente. Así que esto va a ser una gran ventaja para mí. ¿Tienes un enlace a esto en los documentos? No pudo encontrarlo. Aunque es bastante fácil de encontrar en la fuente. –

-1
"SELECT * FROM table WHERE provider IN ({0},{1},{2})".format(*args) #where args is list or tuple of arguments. 
+1

Esto es un poco limitado ya que asume la longitud de la lista, ¿verdad? – jdi

0

probablemente deba realizar la sustitución cadena antes de pasarlo al objeto de cursor para ejecutar:

sql = "SELECT * FROM table WHERE provider IN (%s)" % \ 
     (','.join(str(x) for x in providers)) 
cursor.execute(sql) 
+0

Esto puede ser problemático porque las cadenas no están entre comillas. Tal vez reemplace 'str' con' repr'? – jdi

+0

también podría agregar citas a la unión, por ejemplo. '% ('"' + '","'. join (str (x) para x en proveedores) + '"')' - eso podría verse como un hack de bit aunque supongo –

+0

Pero creo que es necesario para esto solución. – jdi

-1

Por lo tanto, tiene entrada de cadena de ID del requerido:

some_vals = '1 3 5 76 5 4 2 5 7 8'.split() # convert to suitable type if required 
SomeModel.objects.filter(provider__in=some_vals) 
+0

Sí, he preguntado sobre esto en los comentarios principales. OP dijo que hay una razón específica por la que están buscando una consulta en bruto – jdi

+0

@jdi Interesante: si el objeto está dentro del ORM, la consulta SQL se puede recuperar de este respuesta. De lo contrario, solo puedo pensar que están consultando algo fuera del ORM. –

+0

Estoy totalmente de acuerdo contigo en eso, por supuesto. Solo podemos suponer que el OP tiene necesidades que el ORM simplemente no puede cumplir. – jdi

-1

probar esto .... debe trabajo.

SQL = "SELECT * FROM table WHERE provider IN %s"%(providers) 
exec 'cursor.execute("%s")'%(SQL) 
0

Otra respuesta que no me gusta en particular, sino que trabajará para su uso aparente caso:

providers = tuple[str(item) for item in providers] # ('provider1', 'provider2') 
# rest of stuff... 

SQL = 'SELECT * FROM table WHERE provider IN {}'.format(repr(providers)) 
cursor.execute(SQL) 
+0

También podría escribir '' ... {! r} .format (proveedores) 'Supongo que solo depende del gusto –