summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-03-03 13:00:44 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2012-03-03 13:00:44 -0500
commit1607b74f8527905ecdc6133b4b4166a9ed675e09 (patch)
treecd752b16ab90c4864a071689c57f3ff946f8b241 /lib/sqlalchemy/orm
parent4d43079e34a66c3718127266bc5eaa3041c69447 (diff)
downloadsqlalchemy-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.py56
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.