web-dev-qa-db-fra.com

Formatage de la chaîne de requête SQL Python

J'essaie de trouver le meilleur moyen de formater une chaîne de requête SQL. Lorsque je débogue mon application, je souhaite consigner toutes les chaînes de requête SQL dans un fichier. Il est donc important que la chaîne soit correctement formatée.

Option 1

def myquery():
    sql = "select field1, field2, field3, field4 from table where condition1=1 and condition2=2"
    con = mymodule.get_connection()
    ...
  • C'est bon pour imprimer la chaîne SQL.
  • Ce n'est pas une bonne solution si la chaîne est longue et ne correspond pas à la largeur standard de 80 caractères.

Option 2

def query():
    sql = """
        select field1, field2, field3, field4
        from table
        where condition1=1
        and condition2=2"""
    con = mymodule.get_connection()
    ...
  • Ici, le code est clair, mais lorsque vous imprimez la chaîne de requête SQL, vous obtenez tous ces espaces blancs gênants.

    u '\ nsélectionnez champ1, champ2, champ3, champ4\n _ _ ___ de la table\n _ ___ où condition1 = 1\n _ ___ _ et condition2 = 2 '

Remarque: j'ai remplacé les espaces par le trait de soulignement _, car ils sont supprimés par l'éditeur

Option 3

def query():
    sql = """select field1, field2, field3, field4
from table
where condition1=1
and condition2=2"""
    con = mymodule.get_connection()
    ...
  • Je n'aime pas cette option car elle brise la clarté du code bien tabulé.

Option 4

def query():
    sql = "select field1, field2, field3, field4 " \
          "from table " \
          "where condition1=1 " \
          "and condition2=2 "
    con = mymodule.get_connection()    
    ...
  • Je n'aime pas cette option car toute la saisie en plus dans chaque ligne et il est difficile de modifier la requête également.

Pour moi, la meilleure solution serait Option 2 mais je n’aime pas les espaces blancs supplémentaires lors de l’impression de la chaîne SQL.

Connaissez-vous d'autres options?

66
ssoler

Désolé de poster sur un si vieux fil de discussion - mais en tant que personne partageant également une passion pour «le meilleur» de Pythonic, j'ai pensé partager notre solution.

La solution consiste à créer des instructions SQL à l'aide de la concaténation de littéraux de chaînes de python ( http://docs.python.org/ ), ce qui pourrait être qualifié d'un point situé entre Option 2 et Option 4.

Exemple de code:

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

Avantages:

  1. Il conserve le format 'bien tabulé' de Pythonic, mais n'ajoute pas de caractères d'espacement superflus (ce qui pollue la journalisation). 
  2. Cela évite la laideur de l'option antislash de l'option 4, ce qui rend difficile l'ajout de déclarations (sans parler de la cécité des espaces).
  3. De plus, il est très simple de développer l’instruction dans VIM (il suffit de positionner le curseur sur le point d’insertion et d’appuyer sur SHIFT-O pour ouvrir une nouvelle ligne).
96
user590028

Vous avez évidemment envisagé de nombreuses façons d'écrire le code SQL de telle sorte qu'il s'imprime correctement, mais que diriez-vous de modifier l'instruction 'print' que vous utilisez pour la consignation de débogage, plutôt que d'écrire votre code SQL d'une manière qui vous déplaît? En utilisant votre option préférée ci-dessus, que diriez-vous d'une fonction de journalisation telle que celle-ci:

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)

Cela rendrait également trivial l'ajout d'une logique supplémentaire pour fractionner la chaîne journalisée sur plusieurs lignes si la ligne est plus longue que la longueur souhaitée.

16
cdlk

La façon la plus propre que j'ai rencontrée est inspirée par le guide de style sql .

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

Essentiellement, les mots-clés commençant une clause doivent être alignés à droite et les noms de champs, etc., doivent être laissés alignés. Cela semble très soigné et est plus facile à déboguer.

2
aandis
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 la valeur de condition doit être une chaîne, vous pouvez faire comme ceci:

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'"
1
pangpang

Pour éviter formater entièrement, je pense qu'une bonne solution consiste à utiliser procedures .

L'appel d'une procédure vous donne le résultat de la requête que vous souhaitez insérer dans cette procédure. Vous pouvez en fait traiter plusieurs requêtes au sein d'une procédure. L'appel renverra simplement la dernière requête qui a été appelée.

MYSQL

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;

Python

sql =('call example;')
0
Paroofkey
sql = """\
select field1, field2, field3, field4
from table
where condition1=1
and condition2=2
"""

._____. Avoir une chaîne SQL dans une méthode ne signifie pas que vous devez la "tabuler":

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

Je suggérerais une option très facile. il suffit de mettre un r avant la chaîneVous pouvez l'utiliser comme ci-dessous:

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()
0
AB Abhi

En plus de @ user590028: 

Utiliser le format a été utile pour ce sur quoi je travaillais, comme ceci:

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

Et:

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

Je suggérerais de m'en tenir à l'option 2 (je l'utilise toujours pour les requêtes plus complexes que SELECT * FROM table) et si vous voulez l'imprimer de manière agréable, vous pouvez toujours utiliser un module séparé .

0
Michal Chruszcz

Pour les requêtes courtes pouvant tenir sur une ou deux lignes, j'utilise la solution littérale chaîne dans la solution à vote supérieur ci-dessus. Pour les requêtes plus longues, je les décompose en fichiers .sql. J'utilise ensuite une fonction wrapper pour charger le fichier et exécuter le script, quelque chose comme:

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)

Bien sûr, cela habite souvent dans une classe, donc je n'ai généralement pas besoin de passer explicitement cursor. J'utilise aussi généralement codecs.open(), mais cela donne une idée générale. Ensuite, les scripts SQL sont complètement autonomes dans leurs propres fichiers avec leur propre coloration syntaxique.

0
Aikon

vous pouvez mettre les noms de champs dans un tableau "champs", puis:


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