Je cherchais un outil pour formater SQL localement et j'ai trouvé un outil appelé sqlparse alors je l'ai essayé.
https://github.com/andialbrecht/sqlparse
sqlparse est créé par Python et peut être installé à l'aide de pip.
$ pip install sqlparse
sqlparse est utilisé dans un service en ligne appelé SQLFormat, qui vous permet de transmettre et de formater SQL via votre navigateur ou API.
SQLFormat - Online SQL Formatter
Une commande appelée sqlformat qui devient disponible lorsque vous installez sqlparse Si vous entrez SQL en tant que fichier ou entrée standard, le SQL formaté sera généré.
-r
Saut de ligne / retrait,-k upper
Vous pouvez mettre en majuscule les mots-clés avec. Pour d'autres options-h
Vous pouvez le vérifier en option.
$ SQL='select t1.c1 A, t2.c2 B from t1 join t2 on t1.id = t2.id where t1.c1 = "HOGE";'
$ echo "$SQL" | sqlformat -r -k upper -
SELECT t1.c1 A,
t2.c2 B
FROM t1
JOIN t2 ON t1.id = t2.id
WHERE t1.c1 = "HOGE";
sqlparse peut également être utilisé comme bibliothèque.
sqlparse.format vous permet de formater comme la commande sqlformat.
>>> import sqlparse
>>> sql = 'select t1.c1 A, t2.c2 B from t1 join t2 on t1.id = t2.id where t1.c1 = "HOGE";'
>>> print sqlparse.format(sql, reindent=True, keyword_case='upper')
SELECT t1.c1 A,
t2.c2 B
FROM t1
JOIN t2 ON t1.id = t2.id
WHERE t1.c1 = "HOGE";
Vous pouvez obtenir le résultat de l'analyse avec sqlparse.parse. sqlparse.parse renvoie un tuple d'instructions représentant des instructions SQL.
>>> parsed = sqlparse.parse(sql)
>>> parsed
(<Statement 'select...' at 0x1077c6160>,)
sqlparse.parse peut également contenir plusieurs instructions SQL dans son entrée comme suit: Dans ce cas, le taple a plusieurs éléments.
>>> sqlparse.parse("select 1; select 2;")
(<Statement 'select...' at 0x1077c6958>,
<Statement 'select...' at 0x1077c6848>)
Vous pouvez obtenir une liste de jetons avec Statement.tokens.
>>> stmt = parsed[0]
>>> for t in stmt.tokens:
... print type(t), t
...
<class 'sqlparse.sql.Token'> select
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.IdentifierList'> t1.c1 A, t2.c2 B
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Token'> from
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Identifier'> t1
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Token'> join
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Identifier'> t2
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Token'> on
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Comparison'> t1.id = t2.id
<class 'sqlparse.sql.Token'>
<class 'sqlparse.sql.Where'> where t1.c1 = "HOGE";
Il existe différents styles de formatage SQL. Par exemple, les noms de colonne dans la clause SELECT peuvent être répertoriés avec une virgule à la fin de la ligne, comme vous le ferez dans la sortie de sqlformat, ou avec une virgule au début de la ligne.
Vous pouvez modifier la méthode de format dans une certaine mesure avec les options de la méthode de format, mais certaines options telles que la position des virgules ne peuvent pas être gérées.
Modifions le filtre que sqlparse contrôle la méthode de formatage afin que les noms de colonne dans la clause SELECT soient disposés avec la virgule au début.
Tout d'abord, l'implémentation est la suivante pour comprendre le flux de traitement de sqlparse.format.
__init__.py
def format(sql, **options):
"""Format *sql* according to *options*.
Available options are documented in :ref:`formatting`.
In addition to the formatting options this function accepts the
keyword "encoding" which determines the encoding of the statement.
:returns: The formatted SQL statement as string.
"""
encoding = options.pop('encoding', None)
stack = engine.FilterStack()
options = formatter.validate_options(options)
stack = formatter.build_filter_stack(stack, options)
stack.postprocess.append(filters.SerializerUnicode())
return ''.join(stack.run(sql, encoding))
stack = engine.FilterStack()Créer un analyseur avec, stack.run(sql, encoding)Exécute l'analyse SQL donnée dans.
Vous pouvez ajouter des filtres au FilterStack pour contrôler la façon dont il est formaté. Dans sqlparse.format, `` formatter.validate_options '' et `` formatter.build_filter_stack '' sont définis en fonction de la valeur de l'option.
#### **`stack.postprocess.append(filters.SerializerUnicode())Est un filtre pour convertir une liste de jetons en chaîne.`**
Par souci de simplicité, considérons un exemple qui ne prend pas d'options. Commençons par afficher l'entrée telle quelle.
>>> from sqlparse import engine
>>> stack = engine.FilterStack()
>>> stack.postprocess.append(filters.SerializerUnicode())
>>> print stack.run(sql).next()
select t1.c1 A, t2.c2 B from t1 join t2 on t1.id = t2.id where t1.c1 = "HOGE";
sqlparse.filters.L'ajout d'un ReindentFilter entraînera l'indentation des résultats.
#### **`Si vous utilisez un filtre qui traite SQL, tel que ReindentFilter, empilez.enable_grouping()Le regroupement de jetons doit être activé dans.`**
```enable_grouping()Le regroupement de jetons doit être activé dans.
```pycon
>>> from sqlparse.filters import ReindentFilter
>>> stack = engine.FilterStack()
>>> stack.enable_grouping()
>>> stack.stmtprocess.append(ReindentFilter())
>>> stack.postprocess.append(filters.SerializerUnicode())
>>> print stack.run(sql).next()
select t1.c1 A,
t2.c2 B
from t1
join t2 on t1.id = t2.id
where t1.c1 = "HOGE";
Pour modifier le comportement afin que la virgule soit au début, créez une classe qui remplace la
_process_identifierlist '' de `` ReindentFilter```.
from sqlparse.sql import Function
class MyReindentFilter(ReindentFilter):
def _process_identifierlist(self, tlist):
identifiers = list(tlist.get_identifiers())
if len(identifiers) > 1 and not tlist.within(Function):
first = identifiers[0]
self.indent += 1
tlist.insert_before(first, self.nl())
self.offset -= 1
tlist.insert_after(first, self.nl())
for token in identifiers[1:len(identifiers)-1]:
prev = tlist.token_prev(tlist.token_index(token), False)
if prev and prev.is_whitespace():
prev.value = ''
tlist.insert_after(token, self.nl())
last = identifiers[-1]
prev = tlist.token_prev(tlist.token_index(last), False)
if prev and prev.is_whitespace():
prev.value = ''
self.offset += 1
self.indent -= 1
self._process_default(tlist)
reindentfilter
Au lieu demyreindentfilter
Vous pouvez voir qu'il est formaté de sorte que la virgule vienne en premier.
>>> stack = engine.FilterStack()
>>> stack.enable_grouping()
>>> stack.stmtprocess.append(MyReindentFilter())
>>> stack.postprocess.append(filters.SerializerUnicode())
>>> print stack.run(sql).next()
select
t1.c1 A
,t2.c2 B
from t1
join t2 on t1.id = t2.id
where t1.c1 = "HOGE"
and t2.c2 = 1;
Même dans la sous-requête, les noms de colonne sont correctement organisés en fonction de la profondeur de retrait, comme indiqué ci-dessous.
>>> print stack.run('select a, b, c FROM (select a, b, c FROM t1) t2;').next()
select
a
,b
,c
FROM
(select
a
,b
,c
FROM t1) t2;
reindentfilter
D'autres méthodes et filtres vous permettent également de contrôler le retrait de la clause where et la casse des mots-clés.
Recommended Posts