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