OK, youre doing pretty good. theres one behavior of Query which is less than convenient for a case like this, which is that when you use multiple tables in the <whereclause> of a session.query (SomeClass).select(<whereclause>) , namely tables that are outside the scope of the primary table of the mapper which you are querying, it will not make any assumptions whatsoever about the join conditions to those other tables, *even* if those other tables are part of relationships to that mapper.
so you can either explicitly specify all the join conditions in your call to select(), or you can get some help in generating them by using any of the following tools: query.select_by() query.join_by() query.join_via() which *do* make usage of the relations off the mapper, and which are described at: http://www.sqlalchemy.org/docs/ datamapping.myt#datamapping_selectrelations_jointo On Sep 18, 2006, at 9:03 PM, Wyatt Baldwin wrote: > Preface: I'm converting an app from MySQL/MySQLdb to > PostgreSQL/psycopg2/SQLAlchemy. My general SQL experience is limited, > and this is my first time using SQLAlchemy. So far, the conversion > process has been mostly smooth and I've been able to clean up a lot of > things. > > > I've just started getting into the ORM aspects of SQLAlchemy and I'm > trying to do something fairly complicated (I guess): > > - The user enters a free-form street address, which may be only partly > specified (that is, certain parts, like city or zip code might be > missing). > > - The app looks for all streets (AKA edges) in the database that match > what the user entered and returns a list of street objects. Here's the > query I'm trying to use to accomplish this: > > edges = query.select(and_( > func.least(streets.c.addr_f, streets.c.addr_t) <= num, > num <= func.greatest(streets.c.addr_f, streets.c.addr_t), > street_names.c.prefix == street_name.prefix, > street_names.c.name == street_name.name, > street_names.c.sttype == street_name.sttype, > street_names.c.suffix == street_name.suffix > cities.c.city == place.city, > states.c.id == place.state_id, > or_(c.zip_code_l == place.zip_code, c.zip_code_r == > place.zip_code), > )) > > The problem is, in cases where there should be only one result, there > are, for example, 38. The part that seems to be borked is the > street_names stuff (something to do with the way the tables are > joined???). > > The streets table has a foreign key pointer, street_name_id, to the > street names table (see table defs below). If I get the > street_name_ids in a separate query and do the following, I get the > expected number of results: > > edges = query.select(and_( > func.least(streets.c.addr_f, streets.c.addr_t) <= num, > num <= func.greatest(streets.c.addr_f, streets.c.addr_t), > streets.c.street_name_id.in_(*street_name_ids), > cities.c.city == place.city, > states.c.id == place.state_id, > or_(c.zip_code_l == place.zip_code, c.zip_code_r == > place.zip_code), > )) > > > Here's how things are set up (with some stuff left out for clarity): > > Tables > =================== > > streets = Table( > 'layer_streets', > metadata, > Column('id', Integer, primary_key=True), > Column('geom', Geometry, nullable=False), > > Column('node_f_id', Integer, > ForeignKey('layer_nodes.id'), > nullable=False), > Column('node_t_id', Integer, > ForeignKey('layer_nodes.id'), > nullable=False), > > Column('addr_f', Integer), > Column('addr_t', Integer), > > Column('even_side', CHAR(1)), > > Column('street_name_id', Integer, ForeignKey > ('street_names.id'),), > > Column('city_l_id', Integer, ForeignKey('cities.id')), > Column('city_r_id', Integer, ForeignKey('cities.id')), > > Column('state_l_id', CHAR(2), ForeignKey('states.id'), > nullable=False), > Column('state_r_id', CHAR(2), ForeignKey('states.id'), > nullable=False), > > Column('zip_code_l', Integer), > Column('zip_code_r', Integer), > > schema=schema, > ), > > street_names = Table( > 'street_names', > metadata, > Column('id', Integer, primary_key=True), > Column('prefix', String(2)), > Column('name', String, nullable=False), > Column('sttype', String(4)), > Column('suffix', String(2)), > schema=schema, > ), > > > Objects > =================== > > class Street: > """Things and stuff which is not relevant to this discussion.""" > > class StreetName: > """Things and stuff which is not relevant to this discussion.""" > > > Mappers > =================== > > street_name_mapper = orm.mapper( > StreetName, > street_names, > ) > > edge_mapper = orm.mapper( > Street, > layer_streets, > properties={ > 'node_f': orm.relation( > Node, > primaryjoin=layer_streets.c.node_f_id == > layer_nodes.c.id, > ), > 'node_t': orm.relation( > Node, > primaryjoin=layer_streets.c.node_t_id == > layer_nodes.c.id, > ), > 'street_name': orm.relation( > StreetName, > ), > 'city_l': orm.relation( > City, > primaryjoin=layer_streets.c.city_l_id == > cities.c.id, > ), > 'city_r': orm.relation( > City, > primaryjoin=layer_streets.c.city_r_id == > cities.c.id, > ), > 'state_l': orm.relation( > State, > primaryjoin=layer_streets.c.state_l_id == > states.c.id, > ), > 'state_r': orm.relation( > State, > primaryjoin=layer_streets.c.state_r_id == > states.c.id, > ), > } > ) > > > So, the question is, then, of course, what am I doing wrong? Is it the > query? The mapper? Should I define another mapper for this purpose? > Would this be a lot easier if I just knew more about SQL in general? > > Any tips, pointers, or hints will be most appreciated. > > -- > Wyatt Baldwin > byCycle.org > > ---------------------------------------------------------------------- > --- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to > share your > opinions on IT & business topics through brief surveys -- and earn > cash > http://www.techsay.com/default.php? > page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Sqlalchemy-users mailing list > Sqlalchemy-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Sqlalchemy-users mailing list Sqlalchemy-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users