First, tell me if the query I've written below is equivalent to what you're trying to select. The basic idea is that the first nested subquery which joins dkp_run to _last_run_date_by_character is not needed. I'm pretty sure this is the case but you have the more ingrained knowledge of the query plus some test data with which to verify.
SELECT dkp_character.id, dkp_character.name, dkp_run.id FROM dkp_character LEFT OUTER JOIN ( SELECT dkp_dkpattendance.character_id AS character_id, MAX(dkp_run.guild_id) AS last_run_guild_id, MAX(dkp_run.date) AS last_run_date FROM dkp_dkpattendance JOIN dkp_run ON dkp_dkpattendance.run_id = dkp_run.id GROUP BY dkp_dkpattendance.character_id ) AS last_run ON dkp_character.id=last_run.character_id LEFT OUTER JOIN dkp_run ON dkp_run.date=last_run.last_run_date AND dkp_run.guild_id=last_run.last_run_guild_id Next, we can think a bit about ways to issue this query from an ORM perspective. The above query really doesn't seem to me like the intended use case for relation() - you'd in theory be loading a set of Character objects which each refer to a single Run object. But there's really no direct "relation", in the foreign key sense, between Character and Run. Which is why relation() is seeming like an awkward fit. relation()'s primary use, although it can be stretched way beyond this, is to satisfy direct foreign key relationships. relation() can do it - and in fact your original idea of sticking "secondary" in there is possibly a quick way to make this happen (let's label this choice A). But what disturbs me about relying upon that technique is, what if we needed to LEFT OUTER JOIN four levels deep to get to the target table instead of two tables. That was the intuition which told me "don't rely on secondary". We can alternatively use relation() without relying upon "secondary", if we took the intermediary table and placed it as a correlated subquery within the ON clause of dkp_character joining to dkp_run (choice B). Or we could LEFT OUTER JOIN arbitrarily deep by mapping each association unit to a class...but this is likely overkill for the current problem space (choice C). While we do support the use case of a relation() joining on a correlated subquery, it still seems awkward, which still suggests relation() as a less than appropriate place for this. The advantage relation() brings, when used in conjunction with the eager load functionality, is that the extra join for the Run is emitted under a wide variety of circumstances without the need to specify it explicitly. If you didnt need the eager load, a @property which issues the query upon access would do this much more cleanly, and if you didn't need the implicit Run being added to Character in a wide variety of situations, a straight Query which joins everything explicitly would again do this much more cleanly. You've already stated the JOIN is needed as opposed to a separate query, so all that's left is the implicit join functionality which would occur in all situations with just the usage of the eagerload() option. If OTOH the "implicitness" of eagerload() isn't critical, I really wouldn't use relation() to generate the join from dkp_character to dk_run. This query does seem to be specific to one part of the application, in which case I'd spell it out explicitly on an as-needed basis. As far as the Character and Run objects returned, whether or not you use eagerload you still have the option to get back a Character with a Run attached to it, which still would make some usage of relation() (choice D), or you can instead get back 2-tuples each consisting of a Character and a Run object. It is in fact a "named" tuple so you could say "row.Character", "row.Run" (choice E). My own choice would be the last option - the above SQL is rendered using an explicit Query that does the right thing ( I can show you many ways to do that part), and I'd organize the results as tuples since the Character and Run objects are pretty separate from a domain point of view. So weigh out the pros and cons of using relation() with regards to your application's needs, and I can show you how to do any of choice A- E. On Dec 29, 2008, at 4:06 PM, Alan Shields wrote: > > Alrighty, here's a pared down version of what I'm dealing with. > > guild_table = Table( > 'dkp_guild', metadata, > Column('id', Integer, primary_key=True), > Column('name', Unicode(45), nullable=False), > ) > > character_table = Table( > 'dkp_character', metadata, > Column('id', Integer, primary_key=True), > Column('guild_id', Integer, ForeignKey(guild_table.c.id), > nullable=False), > Column('name', Unicode(30)), > ) > > pool_table = Table( > 'dkp_pool', metadata, > Column('id', Integer, primary_key=True), > Column('guild_id', Integer, ForeignKey(guild_table.c.id), > nullable=False), > ) > > event_table = Table( > 'dkp_event', metadata, > Column('id', Integer, primary_key=True), > Column('pool_id', Integer, ForeignKey(pool_table.c.id), > nullable=False), > ) > > run_table = Table( > 'dkp_run', metadata, > Column('id', Integer, primary_key=True), > Column('guild_id', Integer, ForeignKey(guild_table.c.id), > nullable=False), > Column('date', DateTime(timezone=True)), > ) > > dkpattendance_table = Table( > 'dkp_dkpattendance', metadata, > Column('id', Integer, primary_key=True), > Column('character_id', Integer, ForeignKey(character_table.c.id), > nullable=False), > Column('run_id', Integer, ForeignKey(run_table.c.id), > nullable=False), > ) > > character_table = Table( > 'dkp_character', metadata, > Column('id', Integer, primary_key=True), > Column('guild_id', Integer, ForeignKey(guild_table.c.id), > nullable=False), > Column('name', Unicode(30)), > ) > > The SQL query I'm looking to run would be this: > > SELECT dkp_character.id, dkp_character.name, dkp_run.id > FROM dkp_character > LEFT OUTER JOIN (SELECT _last_run_date_by_character.character_id AS > character_id, dkp_run.id AS run_id > FROM (SELECT dkp_dkpattendance.character_id AS > character_id, MAX(dkp_run.guild_id) AS last_run_guild_id, > MAX(dkp_run.date) AS last_run_date > FROM dkp_dkpattendance > JOIN dkp_run ON dkp_dkpattendance.run_id = > dkp_run.id > GROUP BY dkp_dkpattendance.character_id) AS > _last_run_date_by_character > LEFT OUTER JOIN dkp_run ON ( > _last_run_date_by_character.last_run_date = dkp_run.date > AND > _last_run_date_by_character.last_run_guild_id = dkp_run.guild_id) > ) AS _last_run_by_character ON dkp_character.id = > _last_run_by_character.character_id > LEFT OUTER JOIN dkp_run ON _last_run_by_character.run_id = dkp_run.id > ; > > For those following along at home: use attendance records to find out > which runs a character has attended, then grab the most recent ordered > by date. > > I hope this is a bit more intelligble. To be honest, since this is a > one-man project, a lot of times my really bad ideas will keep running > for quite a while. > > Alan > > > --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---