diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-01-13 18:40:36 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-01-13 18:40:36 -0500 |
commit | 5d12891fefa187a15e7dd6f6539c90ce1813aea9 (patch) | |
tree | 1fbbfeb21ada1f027ab7d18daee479acc2d16887 | |
parent | b1c045b40ff48d377aaf689121cfa2d4ab38cc08 (diff) | |
download | sqlalchemy-5d12891fefa187a15e7dd6f6539c90ce1813aea9.tar.gz |
- some changelog / migration stuff, still needs proofreading
-rw-r--r-- | doc/build/changelog/changelog_11.rst | 20 | ||||
-rw-r--r-- | doc/build/changelog/migration_11.rst | 92 | ||||
-rw-r--r-- | doc/build/core/tutorial.rst | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 2 |
4 files changed, 114 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index 975badc36..5fbcca45a 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -22,6 +22,26 @@ :version: 1.1.0b1 .. change:: + :tags: feature, sql + :tickets: 3501 + + A deep improvement to the recently added :meth:`.TextClause.columns` + method, and its interaction with result-row processing, now allows + the columns passed to the method to be positionally matched with the + result columns in the statement, rather than matching on name alone. + The advantage to this includes that when linking a textual SQL statement + to an ORM or Core table model, no system of labeling or de-duping of + common column names needs to occur, which also means there's no need + to worry about how label names match to ORM columns and so-forth. In + addition, the :class:`.ResultProxy` has been further enhanced to + map column and string keys to a row with greater precision in some + cases. + + .. seealso:: + + :ref:`change_3501` + + .. change:: :tags: feature, engine :tickets: 2685 diff --git a/doc/build/changelog/migration_11.rst b/doc/build/changelog/migration_11.rst index b87e7207b..6ee8293f4 100644 --- a/doc/build/changelog/migration_11.rst +++ b/doc/build/changelog/migration_11.rst @@ -445,6 +445,59 @@ will not have much impact on the behavior of the column during an INSERT. :ticket:`3216` +.. _change_3501: + +Positional matching of result columns when using textual SQL +------------------------------------------------------------ + +A series of improvements were made to the :class:`.ResultProxy` system +in the 1.0 series as part of :ticket:`918`, which reorganizes the internals +to match cursor-bound result columns with table/ORM metadata positionally, +rather than by matching names, for compiled SQL constructs that contain full +information about the result rows to be returned. This allows a dramatic savings +on Python overhead as well as much greater accuracy in linking ORM and Core +SQL expressions to result rows. In 1.1, this reorganization has been taken +much further internally, and also has been made available to pure-text SQL +constructs via the use of the recently added :meth:`.TextClause.columns` method. + +The method now accepts column-based arguments positionally which will be matched +to the target result set positionally as well. The key advantage here is that +textual SQL can now be linked to an ORM-level result set without the need to +deal with ambiguous or duplicate column names, or with having to match labeling +schemes to ORM-level column names. All that's needed now is the position:: + + + from sqlalchemy import text + stmt = text("SELECT users.id, addresses.id, users.id, " + "users.name, addresses.email_address AS email " + "FROM users JOIN addresses ON users.id=addresses.user_id " + "WHERE users.id = 1").columns( + User.id, + Address.id, + Address.user_id, + User.name, + Address.email_address + ) + + query = session.query(User).from_statement(text).\ + options(contains_eager(User.addresses)) + result = query.all() + +Above, the textual SQL contains the column "id" three times, which would +normally be ambiguous. Using the new feature, we can apply the mapped +columns from the ``User`` and ``Address`` class directly, even linking +the ``Address.user_id`` column to the ``users.id`` column in textual SQL +for fun, and the :class:`.Query` object will receive rows that are correctly +targetable as needed, including for an eager load. + +.. seealso:: + + :ref:`sqlexpression_text_columns` + + :ref:`behavior_change_3501` + +:ticket:`3501` + .. _change_2528: A UNION or similar of SELECTs with LIMIT/OFFSET/ORDER BY now parenthesizes the embedded selects @@ -896,6 +949,45 @@ Key Behavioral Changes - ORM Key Behavioral Changes - Core ============================= +.. _behavior_change_3501: + +The new behavior of the :meth:`.TextClause.columns` method is that when +columns are passed positionally only, they are linked to the ultimate result set +columns positionally, and no longer on name. Therefore an application that was +using this very recently added method by passing :class:`.Column` objects +to it positionally must ensure that the position of those :class:`.Column` +objects matches the position in which these columns are stated in the +textual SQL. + +E.g., code like the following:: + + stmt = text("SELECT id, name, description FROM table") + + # no longer matches by name + stmt = stmt.columns(my_table.c.name, my_table.c.description, my_table.c.id) + +Would no longer work as expected; the order of the columns given is now +significant:: + + # correct version + stmt = stmt.columns(my_table.c.id, my_table.c.name, my_table.c.description) + +Possibly more likely, a statement that worked like this:: + + stmt = text("SELECT * FROM table") + stmt = stmt.columns(my_table.c.id, my_table.c.name, my_table.c.description) + +is now slightly risky, as the "*" specification will generally deliver columns +in the order in which they are present in the table itself. If the structure +of the table changes due to a migration, this ordering may no longer be the same. +Therefore when using :meth:`.TextClause.columns`, it's advised to list out +the desired columns explicitly, though it's no longer necessary to worry about +duplicate names or names matching. + + +.. seealso:: + + :ref:`change_3501` Dialect Improvements and Changes - Postgresql ============================================= diff --git a/doc/build/core/tutorial.rst b/doc/build/core/tutorial.rst index 053229b8e..0a1398055 100644 --- a/doc/build/core/tutorial.rst +++ b/doc/build/core/tutorial.rst @@ -814,6 +814,8 @@ or special SQL-side processing provided by the datatype. :meth:`.TextClause.bindparams` - full method description +.. _sqlexpression_text_columns: + Specifying Result-Column Behaviors ---------------------------------------------- diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index f18a9cdcd..7fa8f42f8 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -1528,8 +1528,6 @@ class TextClause(Executable, ClauseElement): the result set will match to those columns positionally, meaning the name or origin of the column in the textual SQL doesn't matter:: - stmt = text("SELECT users.id, addresses.id, users.name, ) - stmt = text("SELECT users.id, addresses.id, users.id, " "users.name, addresses.email_address AS email " "FROM users JOIN addresses ON users.id=addresses.user_id " |