@@ -212,6+212,11 @@ But another way, whose usefulness will become apparent later on, is to use the `
{stop}name: jack ; fullname: Jack Jones
name: wendy ; fullname: Wendy Williams
+Result sets which have pending rows remaining should be explicitly closed before discarding. While the resources referenced by the `ResultProxy` will be closed when the object is garbage collected, it's better to make it explicit as some database APIs are very picky about such things:
+
+ {python}
+ >>> result.close()
+
If we'd like to more carefully control the columns which are placed in the COLUMNS clause of the select, we reference individual `Column` objects from our `Table`. These are available as named attributes off the `c` attribute of the `Table` object:
{python}
@@ -301,7+306,7 @@ Most Python operators, as it turns out, produce a SQL expression here, like equa
>>> # reverse works too
>>> print 'fred' > users.c.name
- :users_name > users.name
+ users.name < :users_name
If we add two integer columns together, we get an addition expression:
@@ -579,14+584,305 @@ One more thing though, with automatic labeling applied as well as anonymous alia
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, addresses_1.id AS addresses_1_id, addresses_1.user_id AS addresses_1_user_id, addresses_1.email_address AS addresses_1_email_address
FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? AND (EXISTS (SELECT addresses_1.id
FROM addresses AS addresses_1
WHERE addresses_1.user_id = users.id AND addresses_1.email_address LIKE ?)) ORDER BY users.fullname DESC
['jack', '%@msn.com']
- {stop}Name: jack Email Address jack@yahoo.com
- Name: jack Email Address jack@msn.com
+ {stop}Name: jack ; Email Address jack@yahoo.com
+ Name: jack ; Email Address jack@msn.com
+
+The above example, by it's end, got significantly more intense than the typical end-user constructed SQL will usually be. However when writing higher-level tools such as ORMs, they become more significant. SQLAlchemy's ORM relies very heavily on techniques like this.
+
+## Everything Else {@name=everythingelse}
+
+The concepts of creating SQL expressions have been introduced. What's left are more variants of the same themes. So now we'll catalog the rest of the important things we'll need to know.
+
+### Bind Parameter Objects {@name=bindparams}
+
+Throughout all these examples, SQLAlchemy is busy creating bind parameters wherever literal expressions occur. You can also specify your own bind parameters with your own names, and use the same statement repeatedly. The database dialect converts to the appropriate named or positional style, as here where it converts to positional for SQLite:
+
+ {python}
+ >>> from sqlalchemy.sql import bindparam
+ >>> s = users.select(users.c.name==bindparam('username'))
+Another important aspect of bind paramters is that they may be assigned a type. The type of the bind paramter will determine it's behavior within expressions and also how the data bound to it is processed before being sent off to the database:
+
+ {python}
+ >>> s = users.select(users.c.name.like(bindparam('username', type_=String) + text("'%'")))
+SQL functions are created using the `func` keyword, which generates functions using attribute access:
+
+ {python}
+ >>> from sqlalchemy.sql import func
+ >>> print func.now()
+ now()
+
+ >>> print func.concat('x', 'y')
+ concat(:concat, :concat_1)
+
+Certain functions are marked as "ANSI" functions, which mean they don't get the parenthesis added after them, such as CURRENT_TIMESTAMP:
+
+ {python}
+ >>> print func.current_timestamp()
+ current_timestamp
+
+Functions are most typically used in the columns clause of a select statement, and can also be labeled as well as given a type. Labeling a function is recommended so that the result can be targeted in a result row based on a string name, and assigning it a type is required when you need result-set processing to occur, such as for unicode conversion and date conversions. Below, we use the result function `scalar()` to just read the first column of the first row and then close the result; the label, even though present, is not important in this case:
+ {opensql}SELECT max(addresses.email_address) AS maxemail
+ FROM addresses
+ []
+ {stop}www@www.org
+
+Databases such as Postgres and Oracle which support functions that return whole result sets can be assembled into selectable units, which can be used in statements. Such as, a database function `calculate()` which takes the parameters `x` and `y`, and returns three columns which we'd like to name `q`, `z` and `r`, we can construct using "lexical" column objects as well as bind parameters:
+If we wanted to use our `calculate` statement twice with different bind parameters, the `unique_params()` function will create copies for us, and mark the bind params as "unique" so that conflicting names are isolated. Note we also make two separate aliases of our selectable:
+ WHERE users.id = addresses.user_id) AS address_count
+ FROM users
+ []
+ {stop}[(u'jack', 2), (u'wendy', 2)]
+
+### Correlated Subqueries {@name=correlated}
+
+Notice in the examples on "scalar selects", the FROM clause of each embedded select did not contain the `users` table in it's FROM clause. This is because SQLAlchemy automatically attempts to correlate embeded FROM objects to that of an enclosing query. To disable this, or to specify explicit FROM clauses to be correlated, use `correlate()`:
+
+ {python}
+ >>> s = select([users.c.name], users.c.id==select([users.c.id]).correlate(None))
+ >>> print s
+ SELECT users.name
+ FROM users
+ WHERE users.id = (SELECT users.id
+ FROM users)
+
+ {python}
+ >>> s = select([users.c.name, addresses.c.email_address], users.c.id==
+The `select()` function can take keyword arguments `order_by`, `group_by` (as well as `having`), `limit`, and `offset`. There's also `distinct=True`. These are all also available as generative functions. `order_by()` expressions can use the modifiers `asc()` or `desc()` to indicate ascending or descending.
+
+ {python}
+ >>> s = select([addresses.c.user_id, func.count(addresses.c.id)]).\
-The above example, by it's end, got significantly more intense than the typical end-user constructed SQL will usually be. However when writing higher-level tools such as ORMs, they become more significant. SQLAlchemy's ORM performs transformations like the above in spades.