2017-03-18 137 views
0

我幾乎想出如何此查詢到SQLAlchemy翻譯:的SQLAlchemy從子查詢中有兩個選擇加入

select u.* from (select 
        unit_id, 
        activity, 
        max(occurred_at) maxOA 
        from Activity 
        group by unit_id) a1 

inner join Activity a2 on 
    a2.unit_id = a1.unit_id and a2.occurred_at = a1.maxOA 

inner join Unit u on 
    u.id = a2.unit_id where a2.activity = 'activateReq'; 

我的表是這樣的(GDB是保存我的SQLAlchemy的數據庫連接的全局變量):

class Unit(gDB.Model): 
    __tablename__ = 'Unit' 
    id = gDB.Column('id', gDB.Integer(), primary_key=True) 
    owner_id = gDB.Column('owner_id', gDB.ForeignKey('User.id')) 
    owner = gDB.relationship(User, primaryjoin=owner_id == User.id) 
    unitNumber = gDB.Column('unit_number', gDB.Integer()) 
    street = gDB.Column('street', gDB.String(255)) 
    city = gDB.Column('city', gDB.String(255)) 
    state = gDB.Column('state', gDB.String(2)) 
    zip = gDB.Column('zip', gDB.String(9)) 
    serviceInstallDate = gDB.Column('service_install_date', gDB.DateTime()) 
    activity = gDB.relationship('Activity', backref='unit_id', lazy='select', order_by="desc(Activity.occurredAt)") 

    def __repr__(self): 
     return '<Unit: {0} {1}>'.format(self.unitNumber, self.street) 

class Activity(gDB.Model): 
    __tablename__ = 'Activity' 
    id = gDB.Column('id', gDB.Integer(), primary_key=True) 
    unitID = gDB.Column('unit_id', gDB.ForeignKey('Unit.id')) 
    unit = gDB.relationship(Unit, primaryjoin=unitID == Unit.id) 
    agentID = gDB.Column('agent_id', gDB.ForeignKey('User.id')) 
    agent = gDB.relationship(User, primaryjoin=agentID == User.id) 
    occurredAt = gDB.Column('occurred_at', gDB.DateTime()) 
    activity = gDB.Column('activity', gDB.String(32)) 
    notes = gDB.Column('notes', gDB.String()) 

    def __repr__(self): 
     return '<Activity: {0} {1}>'.format(self.activity, self.occurredAt) 

我這個地步得到:

db.session.query(Activity.unitID, Activity.activity, func.max(Activity.occurredAt).label("maxOA")) 
    .group_by(Activity.unitID) 
    .subquery() 

a2 = expression.alias(Activity) 
u = expression.alias(Unit) 

q = db.session.query(a1) 
    .join(a2, and_(a2.c.unit_id == a1.c.unit_id, a2.c.occurred_at == a1.c.maxOA)) 
    .join(u, u.c.id == a2.c.unit_id).filter(a2.c.activity == 'activateReq') 

q.all() 

q.all()正在返回正確的一組行,但我希望列的Unit,而不是子查詢a1

更新

我已經得到接近:關鍵是要query()所需的列(在這種情況下,u所有列),然後select_from()子查詢a1

q = db.session.query(u).select_from(a1).join(a2, and_(a2.c.unit_id == a1.c.unit_id, a2.c.occurred_at == a1.c.maxOA)).join(u, u.c.id == a2.c.unit_id).filter(a2.c.activity=='activateReq') 

現在的問題是生成的Unit實例沒有相關的Userowner_id/owner)對象;我的神社模板試圖引用user.owner和我

'sqlalchemy.util._collections.result object' has no attribute 'owner' 

我也有不知道這是否是做到這一點的最簡潔或性能方法。

回答

1

啊!我想到了。我正在使用expression.alias()而不是orm.aliased()。它應該是這樣的:

a1 = gDB.session.query(Activity.unitID, Activity.activity, func.max(Activity.occurredAt).label("maxOA")) \ 
    .group_by(Activity.unitID) \ 
    .subquery() 
a2 = aliased(Activity, name="a2") 
u = aliased(Unit, name="u") 
q = gDB.session.query(u).select_from(a1) \ 
    .join(a2, and_(a2.unitID == a1.c.unit_id, a2.occurredAt == a1.c.maxOA)) \ 
    .join(u, u.id == a2.unitID).filter(a2.activity == 'activateReq')