0.7.0b3
=======
- orm
+ - Changed the underlying approach to query.count().
+ query.count() is now in all cases exactly:
+
+ query.
+ from_self(func.count(literal_column('1'))).
+ scalar()
+
+ That is, "select count(1) from (<full query>)".
+ This produces a subquery in all cases, but
+ vastly simplifies all the guessing count()
+ tried to do previously, which would still
+ fail in many scenarios particularly when
+ joined table inheritance and other joins
+ were involved. If the subquery produced
+ for an otherwise very simple count is really
+ an issue, use query(func.count()) as an
+ optimization. [ticket:2093]
+
- some changes to the identity map regarding
rare weakref callbacks during iterations.
The mutex has been removed as it apparently
this is passed through to :meth:`.FromClause.alias`.
If ``None``, a name will be deterministically generated
at compile time.
-
+
"""
return self.enable_eagerloads(False).statement.alias(name=name)
SELECT * FROM (SELECT * FROM X UNION SELECT * FROM y UNION
SELECT * FROM Z)
-
+
Note that many database backends do not allow ORDER BY to
be rendered on a query called within UNION, EXCEPT, etc.
To disable all ORDER BY clauses including those configured
on mappers, issue ``query.order_by(None)`` - the resulting
:class:`.Query` object will not render ORDER BY within
its SELECT statement.
-
+
"""
def distinct(self, *criterion):
"""Apply a ``DISTINCT`` to the query and return the newly resulting
``Query``.
-
+
:param \*expr: optional column expressions. When present,
the Postgresql dialect will render a ``DISTINCT ON (<expressions>>)``
construct.
def count(self):
"""Return a count of rows this Query would return.
+
+ This generates the SQL for this Query as follows::
+
+ SELECT count(1) AS count_1 FROM (
+ SELECT <rest of query follows...>
+ ) AS anon_1
- For simple entity queries, count() issues
- a SELECT COUNT, and will specifically count the primary
- key column of the first entity only. If the query uses
- LIMIT, OFFSET, or DISTINCT, count() will wrap the statement
- generated by this Query in a subquery, from which a SELECT COUNT
- is issued, so that the contract of "how many rows
- would be returned?" is honored.
-
- For queries that request specific columns or expressions,
- count() again makes no assumptions about those expressions
- and will wrap everything in a subquery. Therefore,
- ``Query.count()`` is usually not what you want in this case.
- To count specific columns, often in conjunction with
- GROUP BY, use ``func.count()`` as an individual column expression
- instead of ``Query.count()``. See the ORM tutorial
- for an example.
-
+ Note the above scheme is newly refined in 0.7
+ (as of 0.7b3).
+
+ For fine grained control over specific columns
+ to count, to skip the usage of a subquery or
+ otherwise control of the FROM clause,
+ or to use other aggregate functions,
+ use :attr:`.func` expressions in conjunction
+ with :meth:`~.Session.query`, i.e.::
+
+ from sqlalchemy import func
+
+ # count User records, without
+ # using a subquery.
+ session.query(func.count(User.id))
+
+ # return count of user "id" grouped
+ # by "name"
+ session.query(func.count(User.id)).\\
+ group_by(User.name)
+
+ from sqlalchemy import distinct
+
+ # count distinct "name" values
+ session.query(func.count(distinct(User.name)))
+
"""
- should_nest = [self._should_nest_selectable]
- def ent_cols(ent):
- if isinstance(ent, _MapperEntity):
- return ent.mapper.primary_key
- else:
- should_nest[0] = True
- return [ent.column]
-
- return self._col_aggregate(sql.literal_column('1'), sql.func.count,
- nested_cols=chain(*[ent_cols(ent) for ent in self._entities]),
- should_nest = should_nest[0]
- )
-
- def _col_aggregate(self, col, func, nested_cols=None, should_nest=False):
- context = QueryContext(self)
-
- for entity in self._entities:
- entity.setup_context(self, context)
-
- if context.from_clause:
- from_obj = list(context.from_clause)
- else:
- from_obj = context.froms
-
- if self._enable_single_crit:
- self._adjust_for_single_inheritance(context)
-
- whereclause = context.whereclause
-
- if should_nest:
- if not nested_cols:
- nested_cols = [col]
- else:
- nested_cols = list(nested_cols)
- s = sql.select(nested_cols, whereclause,
- from_obj=from_obj, use_labels=True,
- **self._select_args)
- s = s.alias()
- s = sql.select(
- [func(s.corresponding_column(col) or col)]).select_from(s)
- else:
- s = sql.select([func(col)], whereclause, from_obj=from_obj,
- **self._select_args)
-
- if self._autoflush and not self._populate_existing:
- self.session._autoflush()
- return self.session.scalar(s, params=self._params,
- mapper=self._mapper_zero())
+ col = sql.func.count(sql.literal_column('1'))
+ return self.from_self(col).scalar()
def delete(self, synchronize_session='evaluate'):
"""Perform a bulk delete query.