On Sep 26, 2008, at 12:40 PM, Steven wrote:
>
> I'm new to SQLAlchemy and still getting used to it. I'm trying to
> learn how to use the higer level apis.. the mapped objects. I still
> think in SQL and then have to work "backwards" to figure out how to
> best get SQLAlchemy to do something similar.
well, you're in luck since SQLAlchemy is oriented towards those who
think in terms of SQL.
> ===============================================
> Version1: "one-to-many" group by with count query (2 tables involved:
> user, blogpost). Desired result is list of users with # of blogposts
> for each.
>
> =In SQL:
> select count(*) as cnt, user.name, user.id as name from user, blogpost
> where user.id = blogpost.authorid group by user.name, user.id order by
> user.name asc
To get this query directly:
sess.query(func.count('*').label('cnt'),
User).filter(User.id==BlogPost.authorid).group_by(User.name,
User.id).order_by(User.name.asc())
the FROM clause is generated from what it sees in filter() and
order_by(), so user and blogpost will be there.
> stmt = session.query(blogpost.authorid,
> func
> .count('*').label('post_count')).group_by(blogpost.user_id).subquery()
>
> session.query(User, stmt.c.post_count).outerjoin((stmt,
> User.id==stmt.c.user_id)).order_by(User.id)
so what's happening here is that the docs are pushing more of a
"proper" pattern of relating a table to an aggregate on a related
table, which I believe also performs better. I can't find the link I
usually reference here, but the idea is that instead of grouping on
all the columns of the parent table, you push only exactly what needs
to be grouped into a subquery and then join to that. The previous
method is still entirely fine (although not according to this article
i cant find).
> Although these are doing something slightly different... the
> SQLAlchemy version is doing outer join and returning users with no
> blog posts... don't really need it to be doing that.
well you'd just change "outerjoin" to "join" so that you'd only get
User objects which join to a BlogPost.
> ===============================================
> Version2: "many-to-many" (3 tables involved: tag, tagblogpost and
> blogpost). Desired result: list of tags with number of blog posts
> with that tag
>
> =In SQL we only really have to look at 2 or the 3 tables: tag and
> tagblogpost:
>
> select count(*) as cnt, tag.name, tag.id as name from tag, tagblogpost
> where tag.id = tagblogpost.tagid group by tag.name, tag.id order by
> tag.name asc
So again you can do this more or less directly, where "tagblogpost" is
a Table object, not a mapped association object:
sess.query(func.count("*").label('cnt'),
Tag).filter(Tag.id==tagblogpost.c.tagid).group_by(Tag.name,
Tag.id).order_by(Tag.name.asc())
and the "subquery" approach is again the same idea (here illustrated
using an implicit inner join):
subq = sess.query(tagblogpost.c.tagid,
func.count('*').label('cnt')).group_by(tagblogpost.c.tagid).subquery()
sess.query(Tag,
subq.c.cnt).filter(Tag.id==subq.c.tagid).order_by(Tag.name)
I think you get the idea.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---