Thank you Micheal !
It is the ~any() I was searching for. I should have found it in the
docs myself, but they are so long I think I'll need a month to read
them all :).
The EXISTS is new to me. I said I'm a newbie, so ... :D

For the len thing, I thought it would be more intuitive to do it like
that, but the any() method is just as "clean" and intuitive.

Thanks a lot.
And I really like SQLAlchemy, it is just great. :)

On Dec 18, 5:43 am, Michael Bayer <mike...@zzzcomputing.com> wrote:
> On Dec 17, 2011, at 6:56 PM, Jad Kik wrote:
>
>
>
>
>
>
>
>
>
> > Hi,
> > My problem is with using a many-to-many relationship inside a query.
>
> > I wanted to get all the Customers who are associated to a
> > CustomerGroup, I did:
> > session.query(Customer).filter(Customer.groups.contains(group))
>
> > I wanted to get all the Customers who do not belong to any
> > CustomerGroup. I tried that:
> > session.query(Customer).filter(len(Customer.groups) == 0)
> > which threw an exception "TypeError: object of type
> > 'InstrumentedAttribute' has no len()".
> > I understand what that means, but it would be a good thing to have it
> > available, something similar to Customer.groups.contains().
>
> > I can't seem to do such a thing neither:
> > session.query(Customer).filter([some subquery].count() == 0)
> > Then what would [some subquery] be?
>
> > I did manage to do it with normal SQL (on MySQL 5.1):
> > SELECT c2.id FROM customers c2 WHERE (SELECT COUNT(cg.id) FROM
> > customers c, customergroups cg, customer_group ccg WHERE
> > ccg.customer_id=c.id AND ccg.group_id=cg.id AND c.id=c2.id)=0
> > It worked as I expected.
>
> The usual form of this query is relational terms (the set of all customers) 
> <intersection> (the set of all customer ids in customer_group with N number 
> of group id).   The second half of it uses GROUP BY to group by the customer 
> id and HAVING to limit the rows, and you'd use join() to join the two 
> together as in the form 
> athttp://www.sqlalchemy.org/docs/orm/tutorial.html#using-subqueries.
>
> But here you're looking for the count being zero.   So a subquery against 
> customer_group won't have any rows you'd care about.   To query for an 
> exclusion, use WHERE NOT EXISTS.   In the ORM this is the expression 
> ~Customer.groups.any(), just like the third example 
> athttp://www.sqlalchemy.org/docs/orm/internals.html#sqlalchemy.orm.prop....   
> The join across the association table is handled here within the subquery.
>
> The correlated subquery approach you have is more amenable to being "packaged 
> up" as a simple WHERE criterion on the Python side, but you'll note the 
> format of the query is less well suited to the typical optimizer.  MySQL's 
> optimizer in particular is awful, so this is an example where 
> len(SomeRelationship) might look tidy on the Python side but is actually not 
> taking the reality of the relational database into account to an appropriate 
> degree.    You could achieve that exact form by using the style 
> athttp://www.sqlalchemy.org/docs/orm/tutorial.html#using-subqueriesin 
> conjunction with aliased(Customer) to produce "c2".
>
> I don't know if any of these ways is really "cleaner", except for the ~any() 
> that is only appropriate for the "no groups" comparison.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to