I'm not sure if this is a case of user error or what but I'm trying to use a double sub-query load. The odds are probably pretty good that I'm doing something wrong. I just finally got around to trying subqueryload and I think it is what I've been looking for my entire life. Although the SQL being generated looks incorrect.
The big idea is that I have a list of tours, each tour has a bunch of sights below it that all have images. The tour itself does not have an image. I want to show all the tours with the image of the first sight for that tour. So I'm trying to fire off 3 queries, one to get the tours, one to get the first sight of each tour, and one to get the image of each first sight. I'm using sqlalchemy 0.7.3 in the imperative?(non-declarative) fashion. Here is the relevant tour mapper that makes the tour.first_sight connection: tour_m = mapper(Tour, tours_t, { 'first_sight': relation(Sight, primaryjoin=and_( tours_t.c.id == sights_t.c.tour_id, sights_t.c.parent_sight_id == None, sights_t.c.precedence==0), uselist=False), #.. more stuff }) Here is the relevant image mapper that makes the first_sight.image connection: image_m = mapper(Image, images_t, properties={ # Sights which use this image. 'sights': relation(Sight, backref="image", primaryjoin=and_( images_t.c.id == sights_t.c.image_id, sights_t.c.tour_id == tours_t.c.id, tours_t.c.resource_state != resource_states['REMOVED'])), # More stuff ... }) Here is the usage and error: >>> query = saquery(Tour).join(User, Tour.owner_id == >>> User.id).filter(and_(Tour.resource_state == 1, User.resource_state == 1, >>> Tour.published == >>> True)).order_by(Tour.last_changed_on.desc()).offset(0).limit(101) >>> query = query.options(subqueryload_all('first_sight.image')) >>> query.all() 2011-11-10 11:45:22,112 INFO [sqlalchemy.engine.base.Engine] [MainThread] BEGIN (implicit) 2011-11-10 11:45:22,113 INFO [sqlalchemy.engine.base.Engine] [MainThread] SELECT tours.id AS tours_id, tours.title AS tours_title, tours.summary AS tours_summary, tours.slug AS tours_slug, tours.owner_id AS tours_owner_id, tours.published AS tours_published, tours.created_on AS tours_created_on, tours.resource_state AS tours_resource_state, tours.past_tour_id AS tours_past_tour_id, tours.published_on AS tours_published_on, tours.modified_on AS tours_modified_on, tours.last_changed_on AS tours_last_changed_on, tours.region_id AS tours_region_id FROM tours JOIN users ON tours.owner_id = users.id WHERE tours.resource_state = %(resource_state_1)s AND users.resource_state = %(resource_state_2)s AND tours.published = % (published_1)s ORDER BY tours.last_changed_on DESC LIMIT %(param_1)s OFFSET %(param_2)s 2011-11-10 11:45:22,113 INFO [sqlalchemy.engine.base.Engine] [MainThread] {'param_2': 0, 'param_1': 101, 'published_1': True, 'resource_state_1': 1, 'resource_state_2': 1} 2011-11-10 11:45:22,119 INFO [sqlalchemy.engine.base.Engine] [MainThread] SELECT sights.id AS sights_id, sights.title AS sights_title, sights.summary AS sights_summary, sights.old_scene_id AS sights_old_scene_id, sights.x1_coordinate AS sights_x1_coordinate, sights.y1_coordinate AS sights_y1_coordinate, sights.width AS sights_width, sights.height AS sights_height, sights.precedence AS sights_precedence, sights.old_highlight_description AS sights_old_highlight_description, sights.old_highlight_description_format AS sights_old_highlight_description_format, sights.old_highlight_image_id AS sights_old_highlight_image_id, sights.image_id AS sights_image_id, sights.slice_image_id AS sights_slice_image_id, sights.parent_sight_id AS sights_parent_sight_id, sights.tour_id AS sights_tour_id, sights.subtour_id AS sights_subtour_id, sights.collection_page_id AS sights_collection_page_id, anon_1.tours_id AS anon_1_tours_id FROM (SELECT tours.id AS tours_id FROM tours JOIN users ON tours.owner_id = users.id WHERE tours.resource_state = %(resource_state_1)s AND users.resource_state = %(resource_state_2)s AND tours.published = % (published_1)s ORDER BY tours.last_changed_on DESC LIMIT %(param_1)s OFFSET %(param_2)s) AS anon_1 JOIN sights ON anon_1.tours_id = sights.tour_id AND sights.parent_sight_id IS NULL AND sights.precedence = %(precedence_1)s ORDER BY anon_1.tours_id 2011-11-10 11:45:22,119 INFO [sqlalchemy.engine.base.Engine] [MainThread] {'precedence_1': 0, 'param_1': 101, 'param_2': 0, 'published_1': True, 'resource_state_1': 1, 'resource_state_2': 1} 2011-11-10 11:45:22,121 INFO [sqlalchemy.engine.base.Engine] [MainThread] SELECT images.id AS images_id, images.url AS images_url, images.title AS images_title, images.height AS images_height, images.width AS images_width, images.owner_id AS images_owner_id, images.resource_state AS images_resource_state, images.system AS images_system, images.created_on AS images_created_on, images.modified_on AS images_modified_on, sights_1.image_id AS sights_1_image_id FROM (SELECT tours.id AS tours_id FROM tours JOIN users ON tours.owner_id = users.id WHERE tours.resource_state = %(resource_state_1)s AND users.resource_state = %(resource_state_2)s AND tours.published = % (published_1)s ORDER BY tours.last_changed_on DESC LIMIT %(param_1)s OFFSET %(param_2)s) AS anon_1 JOIN sights AS sights_1 ON anon_1.tours_id = sights_1.tour_id AND sights_1.parent_sight_id IS NULL AND sights_1.precedence = % (precedence_1)s JOIN images ON images.id = sights_1.image_id AND sights_1.tour_id = tours.id AND tours.resource_state != % (resource_state_3)s ORDER BY sights_1.image_id 2011-11-10 11:45:22,122 INFO [sqlalchemy.engine.base.Engine] [MainThread] {'precedence_1': 0, 'param_1': 101, 'param_2': 0, 'resource_state_3': 3, 'resource_state_2': 1, 'resource_state_1': 1, 'published_1': True} Traceback (most recent call last): File "<console>", line 1, in <module> File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/query.py", line 1922, in all return list(self) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/query.py", line 2153, in instances rows = [process[0](row, None) for row in fetch] File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/mapper.py", line 2528, in _instance eager_populators File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/mapper.py", line 2711, in _populators self, row, adapter)): File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/interfaces.py", line 338, in create_row_processor reduced_path, mapper, row, adapter) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/strategies.py", line 894, in create_row_processor lambda x:x[1:] File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/strategies.py", line 891, in <genexpr> (k, [v[0] for v in v]) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/query.py", line 2156, in instances labels) for row in fetch] File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/mapper.py", line 2528, in _instance eager_populators File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/mapper.py", line 2711, in _populators self, row, adapter)): File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/interfaces.py", line 338, in create_row_processor reduced_path, mapper, row, adapter) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/strategies.py", line 894, in create_row_processor lambda x:x[1:] File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/query.py", line 2032, in __iter__ return self._execute_and_instances(context) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/orm/query.py", line 2047, in _execute_and_instances result = conn.execute(querycontext.statement, self._params) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/engine/base.py", line 1399, in execute params) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/engine/base.py", line 1532, in _execute_clauseelement compiled_sql, distilled_params File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/engine/base.py", line 1640, in _execute_context context) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/engine/base.py", line 1633, in _execute_context context) File "/home/ian/workspace/gardentheory/gardentheory/ve/lib/python2.7/ site-packages/sqlalchemy/engine/default.py", line 330, in do_execute cursor.execute(statement, parameters) ProgrammingError: (ProgrammingError) missing FROM-clause entry for table "tours" LINE 5: ...ges.id = sights_1.image_id AND sights_1.tour_id = tours.id A... ^ 'SELECT images.id AS images_id, images.url AS images_url, images.title AS images_title, images.height AS images_height, images.width AS images_width, images.owner_id AS images_owner_id, images.resource_state AS images_resource_state, images.system AS images_system, images.created_on AS images_created_on, images.modified_on AS images_modified_on, sights_1.image_id AS sights_1_image_id \nFROM (SELECT tours.id AS tours_id \nFROM tours JOIN users ON tours.owner_id = users.id \nWHERE tours.resource_state = %(resource_state_1)s AND users.resource_state = %(resource_state_2)s AND tours.published = %(published_1)s ORDER BY tours.last_changed_on DESC \n LIMIT %(param_1)s OFFSET %(param_2)s) AS anon_1 JOIN sights AS sights_1 ON anon_1.tours_id = sights_1.tour_id AND sights_1.parent_sight_id IS NULL AND sights_1.precedence = % (precedence_1)s JOIN images ON images.id = sights_1.image_id AND sights_1.tour_id = tours.id AND tours.resource_state != % (resource_state_3)s ORDER BY sights_1.image_id' {'precedence_1': 0, 'param_1': 101, 'param_2': 0, 'resource_state_3': 3, 'resource_state_2': 1, 'resource_state_1': 1, 'published_1': True} Thanks for your time, -Ian -- 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.