【发布时间】:2016-04-20 14:01:41
【问题描述】:
我如何构建这个 sqlalchemy 查询,以便它做正确的事情?
我已经给出了我能想到的所有别名,但我仍然得到:
ProgrammingError: (psycopg2.ProgrammingError) subquery in FROM must have an alias
LINE 4: FROM (SELECT foo.id AS foo_id, foo.version AS ...
另外,正如 IMSoP 指出的那样,它似乎试图将其转换为交叉连接,但我只是希望它通过同一张表上的子查询组来连接一个表。
这是 sqlalchemy:
(注意:我已将其重写为一个尽可能完整且可以从 python shell 运行的独立文件)
from sqlalchemy import create_engine, func, select
from sqlalchemy import Column, BigInteger, DateTime, Integer, String, SmallInteger
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('postgresql://postgres:#######@localhost:5435/foo1234')
session = sessionmaker()
session.configure(bind=engine)
session = session()
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
__table_args__ = {'schema': 'public'}
id = Column('id', BigInteger, primary_key=True)
time = Column('time', DateTime(timezone=True))
version = Column('version', String)
revision = Column('revision', SmallInteger)
foo_max_time_q = select([
func.max(Foo.time).label('foo_max_time'),
Foo.id.label('foo_id')
]).group_by(Foo.id
).alias('foo_max_time_q')
foo_q = select([
Foo.id.label('foo_id'),
Foo.version.label('foo_version'),
Foo.revision.label('foo_revision'),
foo_max_time_q.c.foo_max_time.label('foo_max_time')
]).join(foo_max_time_q, foo_max_time_q.c.foo_id == Foo.id
).alias('foo_q')
thing = session.query(foo_q).all()
print thing
生成的 sql:
SELECT foo_id AS foo_id,
foo_version AS foo_version,
foo_revision AS foo_revision,
foo_max_time AS foo_max_time,
foo_max_time_q.foo_max_time AS foo_max_time_q_foo_max_time,
foo_max_time_q.foo_id AS foo_max_time_q_foo_id
FROM (SELECT id AS foo_id,
version AS foo_version,
revision AS foo_revision,
foo_max_time_q.foo_max_time AS foo_max_time
FROM (SELECT max(time) AS foo_max_time,
id AS foo_id GROUP BY id
) AS foo_max_time_q)
JOIN (SELECT max(time) AS foo_max_time,
id AS foo_id GROUP BY id
) AS foo_max_time_q
ON foo_max_time_q.foo_id = id
而这是玩具桌:
CREATE TABLE foo (
id bigint ,
time timestamp with time zone,
version character varying(32),
revision smallint
);
我期望得到的 SQL(期望的 SQL)是这样的:
SELECT foo.id AS foo_id,
foo.version AS foo_version,
foo.revision AS foo_revision,
foo_max_time_q.foo_max_time AS foo_max_time
FROM foo
JOIN (SELECT max(time) AS foo_max_time,
id AS foo_id GROUP BY id
) AS foo_max_time_q
ON foo_max_time_q.foo_id = foo.id
最后说明: 如果可能的话,我希望使用 select() 而不是 session.query() 得到答案。谢谢
【问题讨论】:
-
该 SQL 在某些方面似乎不完整/不正确 - 它的
)比(多。但是,我可以看到缺少别名的子查询从第 7 行开始 -FROM (SELECT foo.id AS foo_id,- 并在第 17 行结束 - 单个)。 -
看着它,我认为子查询是由 SQLAlchemy 创建的,因为它将您的查询解释为在
foo和foo_max_time_q(FROM foo, (...) as foo_max_time_q) 之间具有隐含的交叉连接 以及您的显式连接规范 (JOIN (...) AS foo_max_time_q ON foo_max_time_q.foo_id = foo.id)。 -
@IMSoP:这就是它的生成方式。这就是整个问题
-
嗯,这不是整个的问题。 “摆脱错误”不应该是您的目标——如果您设法在第 17 行添加别名,您将在最后一行收到错误 (
) AS foo_q,);解决这个问题,您可能会发现由于我的第二条评论中的问题,查询给出了不正确的结果。相反,“生成所需的 SQL”应该是您的目标。如果手动编写 SQL,生成的 SQL 有何不同?这给你任何线索吗?您能否生成任何表现出相同问题或看起来像所需 SQL 组件的更简单的查询? -
如果我手动编写 SQL,则没有什么可生成的。 SQL 是由 SQLAlchemy 生成的,作为其魔法的一部分。
标签: python postgresql select sqlalchemy psycopg2