Python str(query.compile())。您可以将其调整为使用postgres方言: dialect = postgresql.dialect() str(query.compile(dialect=dialect))

Python str(query.compile())。您可以将其调整为使用postgres方言: dialect = postgresql.dialect() str(query.compile(dialect=dialect)),python,sqlalchemy,Python,Sqlalchemy,并得到一个稍微不同的结果,但仍然没有子查询。很有趣,不是吗?仅供将来参考,query.compile与调用dialent.statement\u编译器(dialent,query,bind=None)相同(简化为) 调用db.session.query(query.all()时,会生成第二个查询(我们将其称为A)。如果您只需键入str(db.session.query(query)),您将看到我们得到一个不同的查询(与N的query.compile())以及一个子查询和一个别名 这和会议有关吗?

并得到一个稍微不同的结果,但仍然没有子查询。很有趣,不是吗?仅供将来参考,
query.compile
与调用
dialent.statement\u编译器(dialent,query,bind=None)相同(简化为)

调用
db.session.query(query.all()
时,会生成第二个查询(我们将其称为A)。如果您只需键入
str(db.session.query(query))
,您将看到我们得到一个不同的查询(与N
query.compile()
)以及一个子查询和一个别名

这和会议有关吗?否-您可以通过将查询转换为
query
对象来检查,而不考虑会话信息:

from sqlalchemy.orm.query import Query
str(Query(query))
窥视实施细节(
Query.\uuu str\uuu
),我们可以看到A的情况是:

context = Query(query)._compile_context()
str(context.statement.compile(bind=None))
context.statement.compile
将尝试选择一种方言(在我们的例子中正确识别Postgres),然后以与S变体相同的方式执行该语句:

dialect.statement_compiler(dialect, context.statement, bind=None)
提醒我们自己,S源自:

dialect = postgresql.dialect()
str(dialect.statement_compiler(dialect, query, bind=None))
这提示我们,在上下文中,有一些东西会改变语句编译器的行为。
方言.statement\u编译器的作用是什么,?它是
SQLCompiler
子类的构造函数,专门从事继承过程,以满足您的方言需求;对于Postgres,它应该是
PGCompiler

注意:我们可以走捷径到a

dialect.statement_compiler(dialect, Query(query).statement, bind=None)
让我们比较编译对象的状态。这可以通过访问编译器的
\uuuu dict\uuu
属性轻松完成:

with_subquery = dialect.statement_compiler(dialect, context.statement, bind=None)
no_subquery = dialect.statement_compiler(dialect, query, bind=None)
from deepdiff import DeepDiff 
DeepDiff(sub.__dict__, nosub.__dict__, ignore_order=True)
重要的是,语句的类型已经改变。这与第一个实例中的情况相同,
context.statement
是一个
sqlalchemy.sql.selectable.Select
对象,而在后者中
query
sqlalchemy.sql.selectable.Alias
对象

这突出了这样一个事实,即使用
db.session.query()
将查询转换为
query
对象会导致编译器根据语句的更改类型采用不同的路径。我们可以看到,S实际上是一个别名,用以下方法包装在select中:

>>> context.statement._froms
[<sqlalchemy.sql.selectable.Alias at 0x7f7e2f4f7160; foo>]
现在您应该很容易地看到,select中包含select意味着在使用
db.session.query(n\u query)
查询数据库时,始终会创建子select

我不知道为什么您显示的第一个查询有一个子查询可见-您当时是否使用过echo(或
str(db.session(n_query))

我可以改变这种行为吗?

当然!只需使用以下命令执行查询:

db.session.execute(n_query)
然后(如果您按照上面的说明启用了echo),您将看到相同的查询(正如您在最后发布的一样)被发出

这与执行别名查询完全相同:

db.session.execute(n_query.alias('foo'))

因为如果没有连续的select,别名就没有用了!

只需猜测第二个问题的后半部分-您的别名()是查询的最后一条语句。根据文档,select()对象上的别名会创建一个命名子查询'(select…)作为aliasname'但在本例中,作为最终语句,它得到了优化,因为在这个查询之外甚至理论上也没有任何东西可以引用它。如果在.alias()之后添加了一些东西并引用“foo”,它会出现吗?如果没有别名,您应该传递core
select()
语句到
Session.execute()
,而不是
Session.query()
。前者执行,而后者构造新的查询(在ORM级别)。
>>> context.statement._froms
[<sqlalchemy.sql.selectable.Alias at 0x7f7e2f4f7160; foo>]
>>> Query(nquery).statement._froms
[<sqlalchemy.sql.selectable.Select at 0x7f7e1e26e668; Select object>]
db.session.execute(n_query)
db.session.execute(n_query.alias('foo'))