Formato de cadena de consulta SQL de Python

Estoy tratando de encontrar la mejor manera de formatear una cadena de consulta SQL. Cuando estoy depurando mi aplicación, me gustaría iniciar sesión para archivar todas las cadenas de consulta de SQL, y es importante que la cadena tenga el formato correcto.

Opción 1

def myquery(): sql = "select field1, field2, field3, field4 from table where condition1=1 and condition2=2" con = mymodule.get_connection() ... 
  • Esto es bueno para imprimir la cadena sql.
  • No es una buena solución si la cadena es larga y no se ajusta al ancho estándar de 80 caracteres.

opcion 2

 def query(): sql = """ select field1, field2, field3, field4 from table where condition1=1 and condition2=2""" con = mymodule.get_connection() ... 
  • Aquí el código es claro, pero cuando imprime la cadena de consulta SQL obtiene todos estos espacios en blanco molestos.

    u ‘\ neleccione campo1, campo2, campo3, campo4 \ ​​n_ _ ___ de la tabla \ n _ ___ donde condición1 = 1 \ n _ ___ _y condición2 = 2′

    Nota: He reemplazado los espacios en blanco con un guión bajo _ , porque están recortados por el editor

    Opcion 3

     def query(): sql = """select field1, field2, field3, field4 from table where condition1=1 and condition2=2""" con = mymodule.get_connection() ... 
    • No me gusta esta opción porque rompe la claridad del código bien tabulado.

    Opcion 4

     def query(): sql = "select field1, field2, field3, field4 " \ "from table " \ "where condition1=1 " \ "and condition2=2 " con = mymodule.get_connection() ... 
    • No me gusta esta opción porque todos los teclados adicionales en cada línea son difíciles de editar también.

    Para mí, la mejor solución sería la Opción 2, pero no me gustan los espacios en blanco adicionales cuando imprimo la cadena sql.

    ¿Conoces alguna otra opción?

    Perdón por publicar en un tema tan antiguo, pero como alguien que también comparte una pasión por el ‘mejor’ de Pythonic, pensé que compartiría nuestra solución.

    La solución es crear sentencias de SQL utilizando la concatenación literal de cadenas de python ( http://docs.python.org/ ), que podría calificarse entre la opción 2 y la opción 4

    Ejemplo de código:

     sql = ('select field1, field2, field3, field4 ' 'from table ' 'where condition1=1 ' 'and condition2=2 ') 

    Pros:

    1. Conserva el formato “bien tabulado” de los pitones, pero no agrega caracteres de espacio extraños (que contaminan el registro).
    2. Evita la continuidad de la barra invertida de la Opción 4, lo que dificulta agregar declaraciones (sin mencionar la ceguera del espacio en blanco).
    3. Y además, es realmente sencillo expandir la statement en VIM (solo coloque el cursor en el punto de inserción y presione MAYÚS-O para abrir una nueva línea).

    Obviamente, ha considerado muchas formas de escribir el SQL de tal manera que se imprima bien, pero ¿qué le parece cambiar la statement de ‘impresión’ que usa para el registro de depuración, en lugar de escribir su SQL de una manera que no le gusta? Usando su opción favorita anterior, ¿qué tal una función de registro como esta:

     def debugLogSQL(sql): print ' '.join([line.strip() for line in sql.splitlines()]).strip() sql = """ select field1, field2, field3, field4 from table""" if debug: debugLogSQL(sql) 

    Esto también haría que sea trivial agregar lógica adicional para dividir la cadena registrada en múltiples líneas si la línea es más larga que la longitud deseada.

     sql = ("select field1, field2, field3, field4 " "from table " "where condition1={} " "and condition2={}").format(1, 2) Output: 'select field1, field2, field3, field4 from table where condition1=1 and condition2=2' 

    Si el valor de la condición debería ser una cadena, puede hacer esto:

     sql = ("select field1, field2, field3, field4 " "from table " "where condition1='{0}' " "and condition2='{1}'").format('2016-10-12', '2017-10-12') Output: "select field1, field2, field3, field4 from table where condition1='2016-10-12' and condition2='2017-10-12'" 

    La forma más limpia que he encontrado está inspirada en la guía de estilo de sql .

     sql = """ SELECT field1, field2, field3, field4 FROM table WHERE condition1 = 1 AND condition2 = 2; """ 

    Esencialmente, las palabras clave que comienzan una cláusula deben estar alineadas a la derecha y los nombres de los campos, etc., deben estar alineados a la izquierda. Esto se ve muy limpio y es más fácil de depurar también.

    podría poner los nombres de los campos en una matriz de “campos”, y luego:

     sql = 'select %s from table where condition1=1 and condition2=2' % ( ', '.join(fields)) 

    Yo sugeriría seguir con la opción 2 (siempre lo estoy usando para consultas más complejas que la SELECT * FROM table ) y si desea imprimirlo de una manera agradable, siempre puede usar un módulo separado .

     sql = """\ select field1, field2, field3, field4 from table where condition1=1 and condition2=2 """ 

    [editar en respuesta a comentario]
    Tener una cadena SQL dentro de un método NO significa que tenga que “tabularlo”:

     >>> class Foo: ... def fubar(self): ... sql = """\ ... select * ... from frobozz ... where zorkmids > 10 ... ;""" ... print sql ... >>> Foo().fubar() select * from frobozz where zorkmids > 10 ; >>> 

    Para consultas breves que pueden caber en una o dos líneas, uso la solución de cadena literal en la solución más votada arriba. Para consultas más largas, las .sql archivos .sql . Luego uso una función de envoltorio para cargar el archivo y ejecutar el script, algo como:

     script_cache = {} def execute_script(cursor,script,*args,**kwargs): if not script in script_cache: with open(script,'r') as s: script_cache[script] = s return cursor.execute(script_cache[script],*args,**kwargs) 

    Por supuesto, esto a menudo vive dentro de una clase, por lo que normalmente no tengo que pasar el cursor explícitamente. En general, también uso codecs.open() , pero esto hace que la idea general se codecs.open() . Luego, los scripts SQL son completamente autónomos en sus propios archivos con su propio resaltado de syntax.

    Además de @ user590028:

    Usar el formato fue útil para lo que estaba trabajando así:

     statement = (ins "(name,standard_price,list_price,mes_type,uom_id,uom_po_id,type,procure_method,cost_method_categ_id,supply_method,sale_ok) " "VALUE ('{0}','{1}','{2}'".format(row[1],str(row[2]),str(row[2])) + ",'fixed',1,1,'product','make_to_stock','standard',1,'buy',True) RETURNING id" ) 

    Y:

     statement = ("INSERT INTO product_product " "(product_tmpl_id,default_code,active,valuation) " "VALUE " "('{0}','{1}',True,'manual_periodic')".format(str(row[0]), row[1]) ) 

    Sugeriría una opción muy fácil. simplemente coloca una r antes de la cadena. Puedes usarla como a continuación:

     query=(r'SELECT f1,f2,f3 ' r'FROM table1 ' r'WHERE f4=cond1 ' r'AND f5=cond2 ') cursor.execute(str(query)) results=cursor.fetchall() cursor.close() 

    Para evitar el formateo completo , creo que una gran solución es utilizar procedimientos .

    Llamar a un procedimiento le da el resultado de cualquier consulta que quiera poner en este procedimiento. En realidad, puede procesar varias consultas dentro de un procedimiento. La llamada solo devolverá la última consulta que fue llamada.

    MyshQL

     DROP PROCEDURE IF EXISTS example; DELIMITER // CREATE PROCEDURE example() BEGIN SELECT 2+222+2222+222+222+2222+2222 AS this_is_a_really_long_string_test; END // DELIMITER; #calling the procedure gives you the result of whatever query you want to put in this procedure. You can actually process multiple queries within a procedure. The call just returns the last query result call example; 

    Pitón

     sql =('call example;')