Hi Mike, Thanks for the help.
I'm not sure that's the right set of subqueries though; looking at the generated SQL, the result seems closer to: CREATE TABLE "#B_temp" AS (SELECT * FROM B WHERE id IN (SELECT max(number) mn FROM B GROUP BY A_id)) CREATE TABLE "#C_temp" AS (SELECT * FROM C WHERE id IN (SELECT max(number) mn FROM C GROUP BY A_id)) SELECT A.*, "#B_temp".*, "#C_temp".* FROM A LEFT OUTER JOIN "#B_temp" ON A.id = "#B_temp".A_id LEFT OUTER JOIN "#C_temp" on A.id = "#C_temp".A_id; And indeed the result of the first q you suggested gives [(A(id = 1, letter = A), 2, 1, u'Bar', 2, None, None, None, None), (A(id = 2, letter = B), None, None, None, None, None, None, None, None), (A(id = 3, letter = C), None, None, None, None, None, None, None, None)] which has too many "None"s. Michael On Tuesday, March 11, 2014 9:55:10 PM UTC-4, Michael Bayer wrote: > > OK subqueries like this: > > bsubq = > session.query(B).filter(B.id.in_(session.query(func.max(B.number)).group_by(B.a_id).as_scalar())).subquery() > csubq = > session.query(C).filter(C.id.in_(session.query(func.max(C.number)).group_by(C.a_id).as_scalar())).subquery() > > > select them all like this: > > q = session.query(A, bsubq, csubq).outerjoin(bsubq, > A.id==bsubq.c.a_id).outerjoin(csubq, A.id==csubq.c.a_id) > print q.all() > > or if you want B C entities: > > q = session.query(A, aliased(B, bsubq), aliased(C, > csubq)).outerjoin(bsubq, A.id==bsubq.c.a_id).outerjoin(csubq, > A.id==csubq.c.a_id) > print q.all() > > > > > On Mar 11, 2014, at 8:23 PM, Michael Weylandt > <michael....@gmail.com<javascript:>> > wrote: > > Sorry for the barrage, Mike. I didn't check my code worked before I posted > (shame on me). I'm looking for: > > CREATE TABLE "#B_temp" AS (SELECT * FROM B WHERE id IN (SELECT id FROM B > JOIN (SELECT max(number) mn FROM B GROUP BY A_id) AS max ON max.mn = > B.number)); > > CREATE TABLE "#C_temp" AS (SELECT * FROM C WHERE id IN (SELECT id FROM C > JOIN (SELECT max(number) mn FROM C GROUP BY A_id) AS max ON max.mn = > C.number)); > > SELECT A.*, "#B_temp".*, "#C_temp".* FROM A LEFT OUTER JOIN "#B_temp" ON > A.id = "#B_temp".A_id LEFT OUTER JOIN "#C_temp" on A.id = "#C_temp".A_id; > > Michael > > On Tuesday, March 11, 2014 7:41:32 PM UTC-4, Michael Bayer wrote: >> >> can you express the exact query you want in SQL? I can translate to >> that easily if you have it. Otherwise if you’re looking to figure out what >> the SQL would be I’d have to find time to look more closely. >> >> >> On Mar 11, 2014, at 7:29 PM, Michael Weylandt <michael....@gmail.com> >> wrote: >> >> Database wizards, >> >> I've got a situation where I have one table with multiple one-to-many >> mappings (i.e., it is the "one" in a "one-to-many" with more than one other >> table). >> >> For each row of the "one", I want to group each of the "many"s by some >> column and do an outer join between the "one" and the "group by max" rows >> of each "many." >> >> Minimal example: >> >> >> ################################################################################################# >> from sqlalchemy import create_engine, Column, String, Integer, ForeignKey >> from sqlalchemy.orm import sessionmaker >> from sqlalchemy.ext.declarative import declarative_base >> >> engine = create_engine("sqlite:///:memory:", echo = True) >> session = sessionmaker(bind = engine)() >> >> Base = declarative_base() >> >> class A(Base): >> __tablename__ = 'A' >> id = Column(Integer, primary_key = True) >> letter = Column(String) >> >> def __repr__(self): >> return "A(id = %s, letter = %s)" % (self.id, self.letter) >> >> class B(Base): >> __tablename__ = 'B' >> id = Column(Integer, primary_key = True) >> A_id = Column(Integer, ForeignKey('A.id'), nullable = False) >> word = Column(String) >> number = Column(Integer) >> >> def __repr__(self): >> return "B(A_id = %s, word = %s, number = %s)" % (self.A_id, >> self.word, self.number) >> >> >> class C(Base): >> __tablename__ = 'C' >> id = Column(Integer, primary_key = True) >> A_id = Column(Integer, ForeignKey('A.id'), nullable = False) >> word = Column(String) >> number = Column(Integer) >> >> def __repr__(self): >> return "B(A_id = %s, word = %s, number = %s)" % (self.A_id, >> self.word, self.number) >> >> Base.metadata.create_all(engine) >> >> session.add_all([ >> A(letter = "A", id = 1), >> A(letter = "B", id = 2), >> A(letter = "C", id = 3), >> ]) >> session.commit() >> >> session.add_all([ >> B(A_id = 1, word = "Foo", number = 1), >> B(A_id = 1, word = "Bar", number = 2), >> B(A_id = 3, word = "Baz", number = 2), >> ]) >> session.commit() >> >> session.add_all([ >> C(A_id = 1, word = "cat", number = 5), >> C(A_id = 2, word = "dog", number = 6), >> C(A_id = 2, word = "cow", number = 2), >> ]) >> session.commit() >> >> ## I want a query which returns >> ## A.letter | B.word | B.number | C.word | C.number >> ## ------------------------------------------------ >> ## A | Bar | 2 | cat | 5 >> ## B | NULL | NULL | dog | 6 >> ## C | Baz | 2 | NULL | NULL >> ## >> ## That is, for each A >> ## 1) Group table B by A_id, and select the B in each group with the >> highest B.number >> ## 1) Group table C by A_id, and select the C in each group with the >> highest C.number >> ## Returning NULL (left outer join) if nothing is found >> >> >> ################################################################################ >> >> I've tried playing with subqueries and func.max and I'm able to get the >> outer join + grouping, but I'm not getting the "max row" for each group. >> Something like this: >> >> >> ################################################################################### >> from sqlalchemy import func >> b_subq = session.query(func.max(B.number).label("b_max"), >> B).group_by(B.A_id).subquery() >> c_subq = session.query(func.max(C.number).label("c_max"), >> C).group_by(C.A_id).subquery() >> >> session.query(A, B, C).outerjoin(B, C).group_by(A).outerjoin(b_subq, >> c_subq).all() ## Fails for some reason >> session.query(A, B, C).outerjoin(B, >> C).outerjoin(b_subq).group_by(A).all() ## Works after removing c_subq >> >> ################################################################################### >> >> Any pointers? >> >> Thanks, >> Michael >> >> (Details: python 2.7.3, sqlalchemy 0.8.1, RHEL 6) >> >> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email tosqlalchemy+...@googlegroups.com. >> To post to this group, send email to sqlal...@googlegroups.com. >> Visit this group at http://groups.google.com/group/sqlalchemy. >> For more options, visit https://groups.google.com/d/optout. >> >> >> > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email tosqlalchemy+...@googlegroups.com <javascript:>. > To post to this group, send email to sqlal...@googlegroups.com<javascript:> > . > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. > > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.