2016-01-15 66 views
4

,使其做正確的事我如何構建這個SQLAlchemy的查詢?的SQLAlchemy:子查詢在FROM必須有一個別名

我給所有我能想到的別名,但我仍然得到:

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 

這裏是噸OY表

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 

最後一點: 我希望用得到答案如果可能的話,選擇()而不是session.query()。謝謝

+0

這SQL似乎是不完整/不正確以某種方式 - 它有更多的')''比('但是,子查詢,我可以看到丟失的別名第7行開始 - 從'(SELECT foo.id AS foo_id,' - 第17行結束 - 一個')' – IMSoP

+0

看着它,我認爲,子查詢已被SQLAlchemy的創建,因爲它解釋你的查詢在foo'之間'暗示交叉聯接和'foo_max_time_q'('FROM FOO,(...),因爲foo_max_time_q')*以及*您明確加入規範('JOIN(...)AS foo_max_time_q ON foo_max_time_q.foo_id = foo.id')。 – IMSoP

+0

@IMSoP 。:這是怎麼回事,雖然產生這是整個問題 – slashdottir

回答

9

你幾乎沒有。做一個"selectable"子查詢,並通過join()與主查詢加入吧:

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 = session.query(
      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) 

print(foo_q.__str__()) 

打印(手動美化):

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(foo.time) AS foo_max_time, 
     foo.id AS foo_id 
    FROM 
     foo 
    GROUP BY foo.id) AS foo_max_time_q 
ON 
    foo_max_time_q.foo_id = foo.id 

完整的工作代碼在此gist可用。

+0

這太酷了。謝謝。它仍然依賴於session.query,但我會接受它。我很難理解爲什麼它如此不同。我想要做的是將整個foo_max_time列聲明爲一個單獨的對象,我可以直接放入。 – slashdottir

+0

所以唯一的區別是foo_q是使用session.query而不是select來完成的嗎?在我看來,這是一個非常微妙的變化,現在對我來說並不直觀。 – slashdottir

+0

好的,我測試過了,它正在工作。這將爲我提高性能。非常感謝 – slashdottir

相關問題