This is just anazing! I was tinkering with the select statement, but
using the correlate_except would never have come to my mind. Thank you!

Am 22.10.2013 00:16, schrieb Michael Bayer:
> if we're talking about just the timestamp, then that would be a column 
> property and if you don't want it to load normally it would be under a 
> deferred().
>
> An analogue of the subquery example using count() is here: 
> http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html#using-column-property
>
> again, you can adapt this to look like your max() + association table:
>
>
> class User(Base):
>     __tablename__ = 'user'
>     id = Column(Integer, primary_key=True)
>
>     address_created = column_property(
>         select([func.max(Address.created)]).\
>               where(Address.id == UserAddresses.address_id).\
>             where(UserAddresses.user_id == id).\
>             correlate_except(Address, UserAddresses)
>     )
>
> On Oct 21, 2013, at 3:12 AM, Sebastian Elsner <sebast...@risefx.com> wrote:
>
>> Thank you for the help! Additionally, I was wondering if it would be
>> able to make "newest_address" an attribute on the user class, which can
>> then be used in a query with ".options(joinedload('newest_address'))".
>> My goal would be that I get an attribute that returns the newest'
>> address date time on normal access and is also able to be eagerly
>> loaded/joined in a query object.  I read up in the docs and either
>> column_property or Correlated Subquery Relatonship Hybrid seems to be
>> made for this. Which one should I use?
>>
>>
>>
>> ButAm 20.10.2013 04:41, schrieb Michael Bayer:
>>> On Oct 19, 2013, at 4:24 PM, Sebastian Elsner <sebast...@risefx.com> wrote:
>>>
>>>> Hello,
>>>>
>>>> using the Address and User example, where the Address is connected to
>>>> the User via a many-to-many relationship, I want to get all users with
>>>> the date of their newest address. This is what I have now:
>>>>
>>>> s.query(User, s.query(func.max(Address.created)).\
>>>> filter(Address.users.any()).correlate(User).as_scalar()).\
>>>>                   outerjoin(User.addresses).all()
>>>>
>>>> But this is giving me all users with the newest address in the whole
>>>> address table. I think the error is in the subquery's filter, but I fail
>>>> to see how I can fix it. I am also not tied to this query, so if you
>>>> know a better way to get a list of all Users and their newest address
>>>> date, shoot!
>>> the format for this is the "select user rows + an aggregate of a related 
>>> table", this format is illustrated here: 
>>> http://docs.sqlalchemy.org/en/rel_0_8/orm/tutorial.html#using-subqueries  
>>> where we illustrate the count of address rows per user. 
>>>
>>> I see here though you have an association table in between them so that 
>>> just has to be added to the subquery to create a row that goes across 
>>> Address and UserAddresses, same idea though, use subquery with aggregate + 
>>> group_by, (outer) join to that:
>>>
>>> subq = session.query(
>>>                func.max(Address.created).label("created"),
>>>                UserAddresses.user_id).join(UserAddresses).\
>>>                group_by(UserAddresses.user_id).subquery()
>>>
>>> q = session.query(User, subq.c.created).outerjoin(subq)
>>> print q.all()
>>>
>>>
>>>
>>>
>>>> Here is a working example. As you can see if you run it, even Users with
>>>> no Addresses assigned will get the newest address date in the query.
>>>>
>>>> import datetime
>>>> from sqlalchemy.ext.declarative import declarative_base
>>>> from sqlalchemy.engine import create_engine
>>>> from sqlalchemy.orm.session import sessionmaker
>>>> from sqlalchemy.schema import Column, ForeignKey
>>>> from sqlalchemy.types import Integer, DateTime, String
>>>> from sqlalchemy.orm import relationship
>>>> from sqlalchemy.sql.expression import func
>>>>
>>>> Base = declarative_base()
>>>>
>>>>
>>>> class Address(Base):
>>>>   __tablename__ = 'address'
>>>>   id = Column(Integer, primary_key=True)
>>>>   created = Column(DateTime)
>>>>   users = relationship('User', back_populates='addresses',
>>>> secondary='useraddress')
>>>>
>>>>   def __repr__(self):
>>>>       return "Address: %s, %s" % (self.id, self.created)
>>>>
>>>>
>>>> class User(Base):
>>>>   __tablename__ = 'user'
>>>>   id = Column(Integer, primary_key=True)
>>>>   name = Column(String)
>>>>   addresses = relationship('Address', back_populates='users',
>>>> secondary='useraddress')
>>>>
>>>>   def __repr__(self):
>>>>       return "User: " + self.name
>>>>
>>>>
>>>> class UserAddresses(Base):
>>>>   __tablename__ = 'useraddress'
>>>>   user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
>>>>   address_id = Column(Integer, ForeignKey('address.id'), primary_key=True)
>>>>
>>>> engine = create_engine('sqlite://')
>>>> Base.metadata.create_all(engine)
>>>> session = sessionmaker(engine)()
>>>>
>>>> u1 = User(name="Foo")
>>>> u2 = User(name="Bar")
>>>> u1.addresses.append(Address(created=datetime.datetime.now()))
>>>> u1.addresses.append(Address(created=datetime.datetime.now() -
>>>> datetime.timedelta(days=1)))
>>>> session.add(u1)
>>>> session.add(u2)
>>>> session.commit()
>>>> print u1, u1.addresses
>>>> print u2, u2.addresses
>>>> print session.query(User, print session.query(User,
>>>> session.query(func.max(Address.created)).filter(Address.users.any()).correlate(User).as_scalar()).outerjoin(User.addresses).all()
>>>>
>>>> Cheers
>>>>
>>>> Sebastian
>>>>
>>>> -- 
>>>> 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/groups/opt_out.
>> -- 
>> 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/groups/opt_out.

-- 
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/groups/opt_out.

Reply via email to