:show-inheritance:
.. autoclass:: Delete
- :members:
+ :members: where
:show-inheritance:
.. autoclass:: FromClause
:show-inheritance:
.. autoclass:: Insert
- :members:
+ :members: prefix_with, values
:show-inheritance:
.. autoclass:: Join
:show-inheritance:
.. autoclass:: Update
- :members:
+ :members: where, values
:show-inheritance:
.. _generic_functions:
>>> str(ins)
'INSERT INTO users (id, name, fullname) VALUES (:id, :name, :fullname)'
-Notice above that the INSERT statement names every column in the ``users`` table. This can be limited by using the ``values`` keyword, which establishes the VALUES clause of the INSERT explicitly::
+Notice above that the INSERT statement names every column in the ``users`` table. This can be limited by using the ``values()`` method, which establishes the VALUES clause of the INSERT explicitly::
- >>> ins = users.insert(values={'name':'jack', 'fullname':'Jack Jones'})
+ >>> ins = users.insert().values(name='jack', fullname='Jack Jones')
>>> str(ins)
'INSERT INTO users (name, fullname) VALUES (:name, :fullname)'
-Above, while the ``values`` keyword limited the VALUES clause to just two columns, the actual data we placed in ``values`` didn't get rendered into the string; instead we got named bind parameters. As it turns out, our data *is* stored within our ``Insert`` construct, but it typically only comes out when the statement is actually executed; since the data consists of literal values, SQLAlchemy automatically generates bind parameters for them. We can peek at this data for now by looking at the compiled form of the statement::
+Above, while the ``values`` method limited the VALUES clause to just two columns, the actual data we placed in ``values`` didn't get rendered into the string; instead we got named bind parameters. As it turns out, our data *is* stored within our ``Insert`` construct, but it typically only comes out when the statement is actually executed; since the data consists of literal values, SQLAlchemy automatically generates bind parameters for them. We can peek at this data for now by looking at the compiled form of the statement::
>>> ins.compile().params #doctest: +NORMALIZE_WHITESPACE
{'fullname': 'Jack Jones', 'name': 'jack'}
.. sourcecode:: pycon+sql
>>> (users.c.id==7).compile().params
- {'id_1': 7}
+ {u'id_1': 7}
Most Python operators, as it turns out, produce a SQL expression here, like equals, not equals, etc.:
WHERE users.id BETWEEN c1.z AND c2.z
>>> s.compile().params
- {'x_2': 5, 'y_2': 12, 'y_1': 45, 'x_1': 17}
+ {u'x_2': 5, u'y_2': 12, u'y_1': 45, u'x_1': 17}
See also :attr:`sqlalchemy.sql.expression.func`.
.. sourcecode:: pycon+sql
>>> # change 'jack' to 'ed'
- {sql}>>> conn.execute(users.update(users.c.name=='jack', values={'name':'ed'})) #doctest: +ELLIPSIS
+ {sql}>>> conn.execute(users.update().where(users.c.name=='jack').values(name='ed')) #doctest: +ELLIPSIS
UPDATE users SET name=? WHERE users.name = ?
['ed', 'jack']
COMMIT
{stop}<sqlalchemy.engine.base.ResultProxy object at 0x...>
>>> # use bind parameters
- >>> u = users.update(users.c.name==bindparam('oldname'), values={'name':bindparam('newname')})
+ >>> u = users.update().where(users.c.name==bindparam('oldname')).values(name=bindparam('newname'))
{sql}>>> conn.execute(u, oldname='jack', newname='ed') #doctest: +ELLIPSIS
UPDATE users SET name=? WHERE users.name = ?
['ed', 'jack']
COMMIT
{stop}<sqlalchemy.engine.base.ResultProxy object at 0x...>
- >>> # update a column to an expression
- {sql}>>> conn.execute(users.update(values={users.c.fullname:"Fullname: " + users.c.name})) #doctest: +ELLIPSIS
+ >>> # update a column to an expression. Send a dictionary to values():
+ {sql}>>> conn.execute(users.update().values({users.c.fullname:"Fullname: " + users.c.name})) #doctest: +ELLIPSIS
UPDATE users SET fullname=(? || users.name)
['Fullname: ']
COMMIT
Correlated Updates
------------------
-
A correlated update lets you update a table using selection from another table, or the same table:
.. sourcecode:: pycon+sql
>>> s = select([addresses.c.email_address], addresses.c.user_id==users.c.id).limit(1)
- {sql}>>> conn.execute(users.update(values={users.c.fullname:s})) #doctest: +ELLIPSIS,+NORMALIZE_WHITESPACE
+ {sql}>>> conn.execute(users.update().values({users.c.fullname:s})) #doctest: +ELLIPSIS,+NORMALIZE_WHITESPACE
UPDATE users SET fullname=(SELECT addresses.email_address
FROM addresses
WHERE addresses.user_id = users.id
COMMIT
{stop}<sqlalchemy.engine.base.ResultProxy object at 0x...>
- {sql}>>> conn.execute(users.delete(users.c.name > 'm')) #doctest: +ELLIPSIS
+ {sql}>>> conn.execute(users.delete().where(users.c.name > 'm')) #doctest: +ELLIPSIS
DELETE FROM users WHERE users.name > ?
['m']
COMMIT
Oracle version 8 through current (11g at the time of this writing) are supported.
Driver
+------
The Oracle dialect uses the cx_oracle driver, available at
-http://python.net/crew/atuining/cx_Oracle/ . The dialect has several behaviors
+http://cx-oracle.sourceforge.net/ . The dialect has several behaviors
which are specifically tailored towards compatibility with this module.
Connecting
+----------
Connecting with create_engine() uses the standard URL approach of
-oracle://user:pass@host:port/dbname[?key=value&key=value...]. If dbname is present, the
+``oracle://user:pass@host:port/dbname[?key=value&key=value...]``. If dbname is present, the
host, port, and dbname tokens are converted to a TNS name using the cx_oracle
-makedsn() function. Otherwise, the host token is taken directly as a TNS name.
+:func:`makedsn()` function. Otherwise, the host token is taken directly as a TNS name.
Additional arguments which may be specified either as query string arguments on the
-URL, or as keyword arguments to create_engine() include:
+URL, or as keyword arguments to :func:`~sqlalchemy.create_engine()` are:
- mode - This is given the string value of SYSDBA or SYSOPER, or alternatively an
- integer value. This value is only available as a URL query string argument.
+* *allow_twophase* - enable two-phase transactions. Defaults to ``True``.
- allow_twophase - enable two-phase transactions. This feature is not yet supported.
+* *auto_convert_lobs* - defaults to True, see the section on LOB objects.
- threaded - defaults to True with SQLAlchemy, enable multithreaded access to
- cx_oracle connections.
+* *auto_setinputsizes* - the cx_oracle.setinputsizes() call is issued for all bind parameters.
+ This is required for LOB datatypes but can be disabled to reduce overhead. Defaults
+ to ``True``.
- use_ansi - defaults to True, use ANSI JOIN constructs (see the section on Oracle 8).
+* *mode* - This is given the string value of SYSDBA or SYSOPER, or alternatively an
+ integer value. This value is only available as a URL query string argument.
- auto_convert_lobs - defaults to True, see the section on LOB objects.
+* *threaded* - enable multithreaded access to cx_oracle connections. Defaults
+ to ``True``. Note that this is the opposite default of cx_oracle itself.
- auto_setinputsizes - the cx_oracle.setinputsizes() call is issued for all bind parameters.
- This is required for LOB datatypes but can be disabled to reduce overhead.
+* *use_ansi* - Use ANSI JOIN constructs (see the section on Oracle 8). Defaults
+ to ``True``. If ``False``, Oracle-8 compatible constructs are used for joins.
- optimize_limits - defaults to False, see the section on LIMIT/OFFSET.
+* *optimize_limits* - defaults to ``False``. see the section on LIMIT/OFFSET.
Auto Increment Behavior
+-----------------------
SQLAlchemy Table objects which include integer primary keys are usually assumed to have
"autoincrementing" behavior, meaning they can generate their own primary key values upon
)
LOB Objects
+-----------
cx_oracle presents some challenges when fetching LOB objects. A LOB object in a result set
is presented by cx_oracle as a cx_oracle.LOB object which has a read() method. By default,
of LOB objects, can be disabled using auto_convert_lobs=False.
LIMIT/OFFSET Support
+--------------------
Oracle has no support for the LIMIT or OFFSET keywords. Whereas previous versions of SQLAlchemy
used the "ROW NUMBER OVER..." construct to simulate LIMIT/OFFSET, SQLAlchemy 0.5 now uses
prefix can be added by enabling the optimize_limits=True flag on create_engine().
Two Phase Transaction Support
+-----------------------------
-Two Phase transactions are partially implemented using XA transactions but at the time of this
-writing have not been successfully tested. The author of cx_oracle also stated that he's never
-seen them work so this may be a cx_oracle issue.
+Two Phase transactions are implemented using XA transactions. Success has been reported of them
+working successfully but this should be regarded as an experimental feature.
Oracle 8 Compatibility
+----------------------
When using Oracle 8, a "use_ansi=False" flag is available which converts all
JOIN phrases into the WHERE clause, and in the case of LEFT OUTER JOIN
makes use of Oracle's (+) operator.
Synonym/DBLINK Reflection
+-------------------------
When using reflection with Table objects, the dialect can optionally search for tables
indicated by synonyms that reference DBLINK-ed tables by passing the flag
"""Support for the PostgreSQL database.
-PostgreSQL supports partial indexes. To create them pass a posgres_where
+Driver
+------
+
+The psycopg2 driver is supported, available at http://pypi.python.org/pypi/psycopg2/ .
+The dialect has several behaviors which are specifically tailored towards compatibility
+with this module.
+
+Note that psycopg1 is **not** supported.
+
+Connecting
+----------
+
+URLs are of the form `postgres://user@password@host:port/dbname[?key=value&key=value...]`.
+
+Postgres-specific keyword arguments which are accepted by :func:`~sqlalchemy.create_engine()` are:
+
+* *server_side_cursors* - Enable the usage of "server side cursors" for SQL statements which support
+ this feature. What this essentially means from a psycopg2 point of view is that the cursor is
+ created using a name, e.g. `connection.cursor('some name')`, which has the effect that result rows
+ are not immediately pre-fetched and buffered after statement execution, but are instead left
+ on the server and only retrieved as needed. SQLAlchemy's :class:`~sqlalchemy.engine.base.ResultProxy`
+ uses special row-buffering behavior when this feature is enabled, such that groups of 100 rows
+ at a time are fetched over the wire to reduce conversational overhead.
+
+Sequences/SERIAL
+----------------
+
+Postgres supports sequences, and SQLAlchemy uses these as the default means of creating
+new primary key values for integer-based primary key columns. When creating tables,
+SQLAlchemy will issue the ``SERIAL`` datatype for integer-based primary key columns,
+which generates a sequence corresponding to the column and associated with it based on
+a naming convention.
+
+To specify a specific named sequence to be used for primary key generation, use the
+:func:`~sqlalchemy.schema.Sequence` construct::
+
+ Table('sometable', metadata,
+ Column('id', Integer, Sequence('some_id_seq'), primary_key=True)
+ )
+
+Currently, when SQLAlchemy issues a single insert statement, to fulfill the contract of
+having the "last insert identifier" available, the sequence is executed independently
+beforehand and the new value is retrieved, to be used in the subsequent insert. Note
+that when an :func:`~sqlalchemy.sql.expression.insert()` construct is executed using
+"executemany" semantics, the sequence is not pre-executed and normal PG SERIAL behavior
+is used.
+
+Postgres 8.3 supports an ``INSERT...RETURNING`` syntax which SQLAlchemy supports
+as well. A future release of SQLA will use this feature by default in lieu of
+sequence pre-execution in order to retrieve new primary key values, when available.
+
+INSERT/UPDATE...RETURNING
+-------------------------
+
+The dialect supports PG 8.3's ``INSERT..RETURNING`` and ``UPDATE..RETURNING`` syntaxes,
+but must be explicitly enabled on a per-statement basis::
+
+ # INSERT..RETURNING
+ result = table.insert(postgres_returning=[table.c.col1, table.c.col2]).\\
+ values(name='foo')
+ print result.fetchall()
+
+ # UPDATE..RETURNING
+ result = table.update(postgres_returning=[table.c.col1, table.c.col2]).\\
+ where(table.c.name=='foo').values(name='bar')
+ print result.fetchall()
+
+Indexes
+-------
+
+PostgreSQL supports partial indexes. To create them pass a postgres_where
option to the Index constructor::
Index('my_index', my_table.c.id, postgres_where=tbl.c.value > 10)
-PostgreSQL 8.2+ supports returning a result set from inserts and updates.
-To use this pass the column/expression list to the postgres_returning
-parameter when creating the queries::
+Transactions
+------------
+
+The Postgres dialect fully supports SAVEPOINT and two-phase commit operations.
+
- raises = tbl.update(empl.c.sales > 100, values=dict(salary=empl.c.salary * 1.1),
- postgres_returning=[empl.c.id, empl.c.salary]).execute().fetchall()
"""
import decimal, random, re, string
Similar functionality is available via the ``insert()`` method on
:class:`~sqlalchemy.schema.Table`.
- table
- The table to be inserted into.
+ :param table: The table to be inserted into.
- values
- A dictionary which specifies the column specifications of the
+ :param values: A dictionary which specifies the column specifications of the
``INSERT``, and is optional. If left as None, the column
specifications are determined from the bind parameters used
during the compile phase of the ``INSERT`` statement. If the
bind parameters also are None during the compile phase, then the
column specifications will be generated from the full list of
- table columns.
+ table columns. Note that the :meth:`~Insert.values()` generative method
+ may also be used for this.
- prefixes
- A list of modifier keywords to be inserted between INSERT and INTO,
- see ``Insert.prefix_with``.
+ :param prefixes: A list of modifier keywords to be inserted between INSERT and INTO.
+ Alternatively, the :meth:`~Insert.prefix_with` generative method may be used.
- inline
+ :param inline:
if True, SQL defaults will be compiled 'inline' into the statement
and not pre-executed.
Similar functionality is available via the ``update()`` method on
:class:`~sqlalchemy.schema.Table`.
- table
- The table to be updated.
+ :param table: The table to be updated.
- whereclause
- A ``ClauseElement`` describing the ``WHERE`` condition of the
- ``UPDATE`` statement.
+ :param whereclause: A ``ClauseElement`` describing the ``WHERE`` condition of the
+ ``UPDATE`` statement. Note that the :meth:`~Update.where()` generative
+ method may also be used for this.
- values
+ :param values:
A dictionary which specifies the ``SET`` conditions of the
``UPDATE``, and is optional. If left as None, the ``SET``
conditions are determined from the bind parameters used during
the compile phase of the ``UPDATE`` statement. If the bind
parameters also are None during the compile phase, then the
``SET`` conditions will be generated from the full list of table
- columns.
+ columns. Note that the :meth:`~Update.values()` generative method may
+ also be used for this.
- inline
+ :param inline:
if True, SQL defaults will be compiled 'inline' into the statement
and not pre-executed.
-
If both `values` and compile-time bind parameters are present, the
compile-time bind parameters override the information specified
within `values` on a per-key basis.
Similar functionality is available via the ``delete()`` method on
:class:`~sqlalchemy.schema.Table`.
- table
- The table to be updated.
+ :param table: The table to be updated.
- whereclause
- A ``ClauseElement`` describing the ``WHERE`` condition of the
- ``UPDATE`` statement.
+ :param whereclause: A :class:`ClauseElement` describing the ``WHERE`` condition of the
+ ``UPDATE`` statement. Note that the :meth:`~Delete.where()` generative method
+ may be used instead.
"""
return Delete(table, whereclause, **kwargs)
Calling styles are of the following forms::
# use on an existing select()
- s = select([<columns>]).where(<criterion>)
+ s = select([table.c.col1]).where(table.c.col2==5)
s = exists(s)
# construct a select() at once
- exists(['*'], **select_arguments).where(<criterion>)
+ exists(['*'], **select_arguments).where(criterion)
# columns argument is optional, generates "EXISTS (SELECT *)"
# by default.
- exists().where(<criterion>)
+ exists().where(table.c.col2==5)
"""
return _Exists(*args, **kwargs)
return select([func.count(col).label('tbl_row_count')], whereclause, from_obj=[self], **params)
def insert(self, values=None, inline=False, **kwargs):
+ """Genrate an :func:`insert()` construct."""
+
return insert(self, values=values, inline=inline, **kwargs)
def update(self, whereclause=None, values=None, inline=False, **kwargs):
+ """Genrate an :func:`update()` construct."""
+
return update(self, whereclause=whereclause, values=values, inline=inline, **kwargs)
def delete(self, whereclause=None, **kwargs):
+ """Genrate a :func:`delete()` construct."""
+
return delete(self, whereclause, **kwargs)
@property
key=<somevalue> arguments
\*args
- deprecated. A single dictionary can be sent as the first positional argument.
+ A single dictionary can be sent as the first positional argument. This allows
+ non-string based keys, such as Column objects, to be used.
"""
if args:
self.parameters.update(kwargs)
class Insert(_ValuesBase):
+ """Represent an INSERT construct.
+
+ The ``Insert`` object is created using the :func:`insert()` function.
+
+ """
def __init__(self, table, values=None, inline=False, bind=None, prefixes=None, **kwargs):
_ValuesBase.__init__(self, table, values)
self._bind = bind
self._prefixes = self._prefixes + [clause]
class Update(_ValuesBase):
+ """Represent an Update construct.
+
+ The ``Update`` object is created using the :func:`update()` function.
+
+ """
def __init__(self, table, whereclause, values=None, inline=False, bind=None, **kwargs):
_ValuesBase.__init__(self, table, values)
self._bind = bind
class Delete(_UpdateBase):
+ """Represent a DELETE construct.
+
+ The ``Delete`` object is created using the :func:`delete()` function.
+
+ """
+
def __init__(self, table, whereclause, bind=None, **kwargs):
self._bind = bind
self.table = table