.. changelog::
:version: 0.9.0
+ .. change::
+ :tags: feature, sql
+ :tickets: 1068
+
+ A :class:`.Label` construct will now render as its name alone
+ in an ``ORDER BY`` clause, if that label is also referred to
+ in the columns clause of the select, instead of rewriting the
+ full expression. This gives the database a better chance to
+ optimize the evaulation of the same expression in two different
+ contexts.
+
.. change::
:tags: feature, firebird
:tickets: 2504
:ticket:`2736`
+Behavioral Improvements
+=======================
+
+Improvements that should produce no compatibility issues, but are good
+to be aware of in case there are unexpected issues.
+
+Label constructs can now render as their name alone in an ORDER BY
+------------------------------------------------------------------
+
+For the case where a :class:`.Label` is used in both the columns clause
+as well as the ORDER BY clause of a SELECT, the label will render as
+just it's name in the ORDER BY clause, assuming the underlying dialect
+reports support of this feature.
+
+E.g. an example like::
+
+ from sqlalchemy.sql import table, column, select, func
+
+ t = table('t', column('c1'), column('c2'))
+ expr = (func.foo(t.c.c1) + t.c.c2).label("expr")
+
+ stmt = select([expr]).order_by(expr)
+
+ print stmt
+
+Prior to 0.9 would render as::
+
+ SELECT foo(t.c1) + t.c2 AS expr
+ FROM t ORDER BY foo(t.c1) + t.c2
+
+And now renders as::
+
+ SELECT foo(t.c1) + t.c2 AS expr
+ FROM t ORDER BY expr
+
+The ORDER BY only renders the label if the label isn't further embedded into an expression within the ORDER BY, other than a simple ``ASC`` or ``DESC``.
+
+The above format works on all databases tested, but might have compatibility issues with older database versions (MySQL 4? Oracle 8? etc.). Based on user reports we can add rules
+that will disable the feature based on database version detection.
+
+:ticket:`1068`
+
Dialect Changes
===============
def visit_clauselist(self, clauselist, order_by_select=None, **kw):
if order_by_select is not None:
- return self._order_by_clauselist(clauselist, order_by_select, **kw)
+ return self._order_by_clauselist(
+ clauselist, order_by_select, **kw)
+
sep = clauselist.operator
if sep is None:
sep = " "
raw_col = set(l._order_by_label_element.name
for l in order_by_select._raw_columns
if l._order_by_label_element is not None)
- def label_ok(c):
- if c._order_by_label_element is not None and \
- c._order_by_label_element.name in raw_col:
- return c._order_by_label_element
- else:
- return None
return ", ".join(
s for s in
(
c._compiler_dispatch(self,
- render_label_as_label=label_ok(c),
- **kw)
+ render_label_as_label=
+ c._order_by_label_element if
+ c._order_by_label_element is not None and
+ c._order_by_label_element.name in raw_col
+ else None,
+ **kw)
for c in clauselist.clauses)
if s)