diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-03-03 13:00:44 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-03-03 13:00:44 -0500 |
| commit | 1607b74f8527905ecdc6133b4b4166a9ed675e09 (patch) | |
| tree | cd752b16ab90c4864a071689c57f3ff946f8b241 /lib/sqlalchemy/orm | |
| parent | 4d43079e34a66c3718127266bc5eaa3041c69447 (diff) | |
| download | sqlalchemy-1607b74f8527905ecdc6133b4b4166a9ed675e09.tar.gz | |
- [feature] Added cte() method to Query,
invokes common table expression support
from the Core (see below). [ticket:1859]
- [feature] Added support for SQL standard
common table expressions (CTE), allowing
SELECT objects as the CTE source (DML
not yet supported). This is invoked via
the cte() method on any select() construct.
[ticket:1859]
Diffstat (limited to 'lib/sqlalchemy/orm')
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index cafce5e3c..5b7f7c9af 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -450,6 +450,62 @@ class Query(object): """ return self.enable_eagerloads(False).statement.alias(name=name) + def cte(self, name=None, recursive=False): + """Return the full SELECT statement represented by this :class:`.Query` + represented as a common table expression (CTE). + + The :meth:`.Query.cte` method is new in 0.7.6. + + Parameters and usage are the same as those of the + :meth:`._SelectBase.cte` method; see that method for + further details. + + Here is the `Postgresql WITH + RECURSIVE example <http://www.postgresql.org/docs/8.4/static/queries-with.html>`_. + Note that, in this example, the ``included_parts`` cte and the ``incl_alias`` alias + of it are Core selectables, which + means the columns are accessed via the ``.c.`` attribute. The ``parts_alias`` + object is an :func:`.orm.aliased` instance of the ``Part`` entity, so column-mapped + attributes are available directly:: + + from sqlalchemy.orm import aliased + + class Part(Base): + __tablename__ = 'part' + part = Column(String) + sub_part = Column(String) + quantity = Column(Integer) + + included_parts = session.query( + Part.sub_part, + Part.part, + Part.quantity).\\ + filter(Part.part=="our part").\\ + cte(name="included_parts", recursive=True) + + incl_alias = aliased(included_parts, name="pr") + parts_alias = aliased(Part, name="p") + included_parts = included_parts.union( + session.query( + parts_alias.part, + parts_alias.sub_part, + parts_alias.quantity).\\ + filter(parts_alias.part==incl_alias.c.sub_part) + ) + + q = session.query( + included_parts.c.sub_part, + func.sum(included_parts.c.quantity).label('total_quantity') + ).\ + group_by(included_parts.c.sub_part) + + See also: + + :meth:`._SelectBase.cte` + + """ + return self.enable_eagerloads(False).statement.cte(name=name, recursive=recursive) + def label(self, name): """Return the full SELECT statement represented by this :class:`.Query`, converted to a scalar subquery with a label of the given name. |
