oracle 如何在SQLAlchemy中漂亮地格式化SQL查询的打印?

gtlvzcf8  于 2023-02-21  发布在  Oracle
关注(0)|答案(5)|浏览(223)

我正在使用SQLAlchemy动态生成PL/SQL,使用compile并设置dialectcompile_kwargs参数(例如,使用str(ins.compile(dialect=oracle.dialect(), compile_kwargs={'literal_binds': True})))。这工作得很好,除了输出不是用最漂亮的SQL语句格式化的。
例如,我的一个输出如下所示:

INSERT INTO my_table (a, b, c) SELECT my_table2.d, bar.e, bar.f 
FROM my_table2 JOIN (SELECT my_table3.e AS e, max(my_table3.f) AS f, count(my_table3.g) AS g 
FROM my_table3 
WHERE my_table3.h = 'foo' GROUP BY my_table3.e 
HAVING count(my_table3.g) = 1) bar ON my_table2.g = bar.g

相反,我希望将其打印出来,如下所示:

INSERT INTO my _table (a, b c)
SELECT my_table2.d, bar.e, bar.f
FROM my_table2 JOIN (
    SELECT my_table3.e, max(my_table3.f), count(my_table3.g)
    FROM my_table3
    WHERE my_table3.h = 'foo'
    GROUP BY my_table3.e
    HAVING count(my_table3.g) = 1
) bar ON my_table2.g = bar.g

如何让SQLAlchemy漂亮地打印SQL语句?
要复制:

from sqlalchemy import table, column, String, Numeric, func, select
from sqlalchemy.dialects import oracle
my_table = table('my_table', column('a', String), column('b', String), column('c', String))
my_table2 = table('my_table2', column('d', String), column('g', String))
my_table3 = table('my_table3', column('d', String), column('e', String), column('f', Numeric), column('g', String), column('h', String))

inner_sel = select([my_table3.c.e, func.max(my_table3.c.f).label('f'), func.count(my_table3.c.g).label('g')]).where(my_table3.c.h=='foo').group_by(my_table3.c.e).having(func.count(my_table3.c.g)==1).alias('bar')

outer_sel = select([my_table2.c.d, inner_sel.c.e, inner_sel.c.f]).select_from(my_table2.join(inner_sel, my_table2.c.g==inner_sel.c.g))

ins = my_table.insert().from_select([my_table.c.a, my_table.c.b, my_table.c.c], outer_sel)

print ins.compile(dialect=oracle.dialect(), compile_kwargs={'literal_binds': True})
vdzxcuhz

vdzxcuhz1#

您可以使用sqlparse包和sqlparse.format(sql, reindent=True, keyword_case='upper')应该做您想要的?

zazmityj

zazmityj2#

项目sqlparse已经成熟(10年以上),并且仍然非常活跃。sqlparse旨在解析、拆分和格式化SQL语句。
以下示例使用sqlparse来美化SQL文件的格式:

import argparse
import sqlparse

# Parse command line arguments
parser = argparse.ArgumentParser(prog="pretty_print_sql")
parser.add_argument("file", type=argparse.FileType("r"), nargs="+")
args = parser.parse_args()

# Pretty print input files
for file in args.file:
    print(sqlparse.format(file.read(), reindent=True, keyword_case='upper'))

要使用pip安装sqlparse以供个人使用:

python3 -m pip install sqlparse --user --upgrade

要使用pipenv安装sqlparse(在项目内):

python3 -m pipenv install sqlparse
j2cgzkjk

j2cgzkjk4#

试试这个猴子补丁:
pip install sqlparse

### monkeypatching SQL'Alchemy for pretty SQL query printing (((
from sqlalchemy.log import InstanceLogger

def pretty_log(self, level, msg, *args, **kwargs):
    if self.logger.manager.disable >= level:
        return

    selected_level = self._echo_map[self.echo]
    if selected_level == logging.NOTSET:
        selected_level = self.logger.getEffectiveLevel()

    if level >= selected_level:

        import sqlparse
        ### HERE IT IS ###
        msg = sqlparse.format(msg, reindent=True, keyword_case='upper')

        self.logger._log(level, '\n'+msg, args, **kwargs)

InstanceLogger.log = pretty_log
### )))
iqxoj9l9

iqxoj9l95#

按照@v_retoux和@olibre的例子,我在GitHub上创建了一个易于部署的脚本,它使用sqlparse处理一个或多个sql文件,并且有一个干净的输出,可以通过管道传输单个文件。
以下是来源:

import argparse, sqlparse, re

parser = argparse.ArgumentParser(prog="sqlpp")
parser.add_argument("--verbose", "-v", action='store_true')
parser.add_argument("file", type=argparse.FileType("r"), nargs="+")

args = parser.parse_args()

def prepend(s, s2): return s2 + re.sub('\n', '\n'+s2, s)

# Pretty print input files
n=len(args.file)
for i, file in enumerate(args.file):
    sIn = file.read().replace('\n', '')
    file.close()
    sOut = sqlparse.format(sIn, reindent=True, keyword_case='upper')
    if args.verbose or n > 1: 
        print("File{0}:\n    {1}\n{2}\nFormatted SQL:\n{3}\n".format(
             (' ' + str(i+1) if n > 1 else '')
            ,file.name
            ,("\nOriginal SQL:\n{}\n".format(prepend(sIn, "    ")) 
                    if args.verbose else "")
            ,prepend(sOut, "    ")
        ))
    else:
        print(sOut)

相关问题