BTW, this post started out as a reply to James but grew into a collective summary of my thoughts on the entire thread so far. You've been warned :)
James Taylor wrote: > But wouldn't the join from orders to items be OUTER in this case > since you can have orders with a total > 50 but no items. (Your > application logic probably forbids this, but it is allowed at the > relational level). > > Gets complicated quick! Yes, that's one of the things I started to dislike as I got more into the details. The 'obj1.obj2.obj3' join syntax does not imply the type of join (i.e. inner, outer, cross, etc.). My initial thought is to say that this type of join syntax would always use inner joins, which is easy enough to remember. One thing I'm not quite clear on is how the join type is specified with the other join syntaxes in SA. There's join_to/join_via and Mike talked about from_obj=[users.join(ordertable).join(...)], but both of those are just as ambiguous as obj1.obj2.obj3 when it comes to the join type (and they're a lot more verbose at that). I guess SelectResults has outerjoin_to()...more on that later. Here is a more complete join syntax proposal: INNER JOIN (join path syntax sugar): User.c.orders User.c.orders.items INNER JOIN (non-sugar): join(User.c.orders) join(User.c.orders.items) join(User, Order, User.c.user_id > Order.c.user_id) OUTER JOIN: outerjoin(User.c.orders) outerjoin(User.c.orders.items) outerjoin(User, Order, User.c.user_id > Order.c.user_id) RANDOM JOIN: random_join(User.c.orders) Just kidding on that last one :P Each join function requires one or three positional arguments. The single-arg version takes a join path as it's argument, and performs the join type represented by function on all joins along the path. A stand-alone join path is syntax sugar for join(<join path>). The three-arg version takes two join-able objects and a condition on which to join them. I realize that a two-arg version is also available where SA tries to find a relationship between the first two args, and IMHO that should be deprecated because it is error-prone. To do a join based on a mapper relationship, use a join path. To do an ad-hoc join use the three-argument version. In addition to join paths and classes, the 3-arg version should also accept tables, strings (entity names), select clauses, and other join objects as arguments. When using anything other than a join path as the first argument, three arguments are required. So this: outerjoin( join(User.c.orders), Items, Order.c.order_id == Item.c.order_id ) and would generate this: FROM users INNER JOIN orders ON users.user_id = orders.user_id LEFT OUTER JOIN items ON orders.order_id = items.order_id An optional 'alias' keyword argument may also be specified in a join function. If the single-arg version is used then the alias applies to the last table in the join path. Otherwise the alias applies to the second argument. join(User.c.orders, alias='ox') join( User, Order, User.c.user_id == Order.c.user_id, alias='ox' ) both of these expressions generate the following (pseudo) SQL: FROM users LEFT OUTER JOIN orders ox ON users.user_id = ox.user_id Possible alternative syntax: User.c.join(Order) The biggest problem with this alternative is that it clutters the User.c namespace. Like we were saying earlier: > One thing we might want to change is the 'alias' function. > Since the 'orders' table may have a column named 'alias', it might > be better to make it a stand-alone function like this: > alias(c.orders, 'ox') > > Mike wrote: >> i think this is the problem when you start munging namespaces >> together, as opposed to grouping them under explicit prefixes (i.e. >> 'c'). But 'c' is actually a conglomeration of namespaces including columns, functions, operations, etc. 'c' should only contain columns and relationships and everything else should be moved to a separate package (maybe sqlalchemy.query or even the root sqlalchemy package). I also think something similar to the SelectResults "transformative" style of creating joins would be useful if it was built-in to Query (with a few name changes such as 'join_to' should be 'join' and 'outerjoin_to' should be 'outer_join'). One thing I don't like about SelectResults is that it gives special attention to a few functions (avg, sum, min, max, etc.). These functions can incorporated into a query with the more versatile 'func.xyz' syntax, and would just add to the confusion about how to use functions. Anyway, there's another brain dump for now. ~ Daniel --~--~---------~--~----~------------~-------~--~----~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---