~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to doc/_sources/core/constraints.txt

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski
  • Date: 2013-10-28 22:29:40 UTC
  • mto: (1.6.9)
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: package-import@ubuntu.com-20131028222940-t6h277tm5kaiepk4
Tags: upstream-0.8.3
Import upstream version 0.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
.. _metadata_constraints_toplevel:
 
2
.. _metadata_constraints:
 
3
 
 
4
.. module:: sqlalchemy.schema
 
5
 
 
6
=================================
 
7
Defining Constraints and Indexes
 
8
=================================
 
9
 
 
10
.. _metadata_foreignkeys:
 
11
 
 
12
This section will discuss SQL :term:`constraints` and indexes.  In SQLAlchemy
 
13
the key classes include :class:`.ForeignKeyConstraint` and :class:`.Index`.
 
14
 
 
15
Defining Foreign Keys
 
16
---------------------
 
17
 
 
18
A *foreign key* in SQL is a table-level construct that constrains one or more
 
19
columns in that table to only allow values that are present in a different set
 
20
of columns, typically but not always located on a different table. We call the
 
21
columns which are constrained the *foreign key* columns and the columns which
 
22
they are constrained towards the *referenced* columns. The referenced columns
 
23
almost always define the primary key for their owning table, though there are
 
24
exceptions to this. The foreign key is the "joint" that connects together
 
25
pairs of rows which have a relationship with each other, and SQLAlchemy
 
26
assigns very deep importance to this concept in virtually every area of its
 
27
operation.
 
28
 
 
29
In SQLAlchemy as well as in DDL, foreign key constraints can be defined as
 
30
additional attributes within the table clause, or for single-column foreign
 
31
keys they may optionally be specified within the definition of a single
 
32
column. The single column foreign key is more common, and at the column level
 
33
is specified by constructing a :class:`~sqlalchemy.schema.ForeignKey` object
 
34
as an argument to a :class:`~sqlalchemy.schema.Column` object::
 
35
 
 
36
    user_preference = Table('user_preference', metadata,
 
37
        Column('pref_id', Integer, primary_key=True),
 
38
        Column('user_id', Integer, ForeignKey("user.user_id"), nullable=False),
 
39
        Column('pref_name', String(40), nullable=False),
 
40
        Column('pref_value', String(100))
 
41
    )
 
42
 
 
43
Above, we define a new table ``user_preference`` for which each row must
 
44
contain a value in the ``user_id`` column that also exists in the ``user``
 
45
table's ``user_id`` column.
 
46
 
 
47
The argument to :class:`~sqlalchemy.schema.ForeignKey` is most commonly a
 
48
string of the form *<tablename>.<columnname>*, or for a table in a remote
 
49
schema or "owner" of the form *<schemaname>.<tablename>.<columnname>*. It may
 
50
also be an actual :class:`~sqlalchemy.schema.Column` object, which as we'll
 
51
see later is accessed from an existing :class:`~sqlalchemy.schema.Table`
 
52
object via its ``c`` collection::
 
53
 
 
54
    ForeignKey(user.c.user_id)
 
55
 
 
56
The advantage to using a string is that the in-python linkage between ``user``
 
57
and ``user_preference`` is resolved only when first needed, so that table
 
58
objects can be easily spread across multiple modules and defined in any order.
 
59
 
 
60
Foreign keys may also be defined at the table level, using the
 
61
:class:`~sqlalchemy.schema.ForeignKeyConstraint` object. This object can
 
62
describe a single- or multi-column foreign key. A multi-column foreign key is
 
63
known as a *composite* foreign key, and almost always references a table that
 
64
has a composite primary key. Below we define a table ``invoice`` which has a
 
65
composite primary key::
 
66
 
 
67
    invoice = Table('invoice', metadata,
 
68
        Column('invoice_id', Integer, primary_key=True),
 
69
        Column('ref_num', Integer, primary_key=True),
 
70
        Column('description', String(60), nullable=False)
 
71
    )
 
72
 
 
73
And then a table ``invoice_item`` with a composite foreign key referencing
 
74
``invoice``::
 
75
 
 
76
    invoice_item = Table('invoice_item', metadata,
 
77
        Column('item_id', Integer, primary_key=True),
 
78
        Column('item_name', String(60), nullable=False),
 
79
        Column('invoice_id', Integer, nullable=False),
 
80
        Column('ref_num', Integer, nullable=False),
 
81
        ForeignKeyConstraint(['invoice_id', 'ref_num'], ['invoice.invoice_id', 'invoice.ref_num'])
 
82
    )
 
83
 
 
84
It's important to note that the
 
85
:class:`~sqlalchemy.schema.ForeignKeyConstraint` is the only way to define a
 
86
composite foreign key. While we could also have placed individual
 
87
:class:`~sqlalchemy.schema.ForeignKey` objects on both the
 
88
``invoice_item.invoice_id`` and ``invoice_item.ref_num`` columns, SQLAlchemy
 
89
would not be aware that these two values should be paired together - it would
 
90
be two individual foreign key constraints instead of a single composite
 
91
foreign key referencing two columns.
 
92
 
 
93
.. _use_alter:
 
94
 
 
95
Creating/Dropping Foreign Key Constraints via ALTER
 
96
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
97
 
 
98
In all the above examples, the :class:`~sqlalchemy.schema.ForeignKey` object
 
99
causes the "REFERENCES" keyword to be added inline to a column definition
 
100
within a "CREATE TABLE" statement when
 
101
:func:`~sqlalchemy.schema.MetaData.create_all` is issued, and
 
102
:class:`~sqlalchemy.schema.ForeignKeyConstraint` invokes the "CONSTRAINT"
 
103
keyword inline with "CREATE TABLE". There are some cases where this is
 
104
undesireable, particularly when two tables reference each other mutually, each
 
105
with a foreign key referencing the other. In such a situation at least one of
 
106
the foreign key constraints must be generated after both tables have been
 
107
built. To support such a scheme, :class:`~sqlalchemy.schema.ForeignKey` and
 
108
:class:`~sqlalchemy.schema.ForeignKeyConstraint` offer the flag
 
109
``use_alter=True``. When using this flag, the constraint will be generated
 
110
using a definition similar to "ALTER TABLE <tablename> ADD CONSTRAINT <name>
 
111
...". Since a name is required, the ``name`` attribute must also be specified.
 
112
For example::
 
113
 
 
114
    node = Table('node', meta,
 
115
        Column('node_id', Integer, primary_key=True),
 
116
        Column('primary_element', Integer,
 
117
            ForeignKey('element.element_id', use_alter=True, name='fk_node_element_id')
 
118
        )
 
119
    )
 
120
 
 
121
    element = Table('element', meta,
 
122
        Column('element_id', Integer, primary_key=True),
 
123
        Column('parent_node_id', Integer),
 
124
        ForeignKeyConstraint(
 
125
            ['parent_node_id'],
 
126
            ['node.node_id'],
 
127
            use_alter=True,
 
128
            name='fk_element_parent_node_id'
 
129
        )
 
130
    )
 
131
 
 
132
ON UPDATE and ON DELETE
 
133
~~~~~~~~~~~~~~~~~~~~~~~
 
134
 
 
135
Most databases support *cascading* of foreign key values, that is the when a
 
136
parent row is updated the new value is placed in child rows, or when the
 
137
parent row is deleted all corresponding child rows are set to null or deleted.
 
138
In data definition language these are specified using phrases like "ON UPDATE
 
139
CASCADE", "ON DELETE CASCADE", and "ON DELETE SET NULL", corresponding to
 
140
foreign key constraints. The phrase after "ON UPDATE" or "ON DELETE" may also
 
141
other allow other phrases that are specific to the database in use. The
 
142
:class:`~sqlalchemy.schema.ForeignKey` and
 
143
:class:`~sqlalchemy.schema.ForeignKeyConstraint` objects support the
 
144
generation of this clause via the ``onupdate`` and ``ondelete`` keyword
 
145
arguments. The value is any string which will be output after the appropriate
 
146
"ON UPDATE" or "ON DELETE" phrase::
 
147
 
 
148
    child = Table('child', meta,
 
149
        Column('id', Integer,
 
150
                ForeignKey('parent.id', onupdate="CASCADE", ondelete="CASCADE"),
 
151
                primary_key=True
 
152
        )
 
153
    )
 
154
 
 
155
    composite = Table('composite', meta,
 
156
        Column('id', Integer, primary_key=True),
 
157
        Column('rev_id', Integer),
 
158
        Column('note_id', Integer),
 
159
        ForeignKeyConstraint(
 
160
                    ['rev_id', 'note_id'],
 
161
                    ['revisions.id', 'revisions.note_id'],
 
162
                    onupdate="CASCADE", ondelete="SET NULL"
 
163
        )
 
164
    )
 
165
 
 
166
Note that these clauses are not supported on SQLite, and require ``InnoDB``
 
167
tables when used with MySQL. They may also not be supported on other
 
168
databases.
 
169
 
 
170
 
 
171
UNIQUE Constraint
 
172
-----------------
 
173
 
 
174
Unique constraints can be created anonymously on a single column using the
 
175
``unique`` keyword on :class:`~sqlalchemy.schema.Column`. Explicitly named
 
176
unique constraints and/or those with multiple columns are created via the
 
177
:class:`~sqlalchemy.schema.UniqueConstraint` table-level construct.
 
178
 
 
179
.. sourcecode:: python+sql
 
180
 
 
181
    meta = MetaData()
 
182
    mytable = Table('mytable', meta,
 
183
 
 
184
        # per-column anonymous unique constraint
 
185
        Column('col1', Integer, unique=True),
 
186
 
 
187
        Column('col2', Integer),
 
188
        Column('col3', Integer),
 
189
 
 
190
        # explicit/composite unique constraint.  'name' is optional.
 
191
        UniqueConstraint('col2', 'col3', name='uix_1')
 
192
        )
 
193
 
 
194
CHECK Constraint
 
195
----------------
 
196
 
 
197
Check constraints can be named or unnamed and can be created at the Column or
 
198
Table level, using the :class:`~sqlalchemy.schema.CheckConstraint` construct.
 
199
The text of the check constraint is passed directly through to the database,
 
200
so there is limited "database independent" behavior. Column level check
 
201
constraints generally should only refer to the column to which they are
 
202
placed, while table level constraints can refer to any columns in the table.
 
203
 
 
204
Note that some databases do not actively support check constraints such as
 
205
MySQL.
 
206
 
 
207
.. sourcecode:: python+sql
 
208
 
 
209
    meta = MetaData()
 
210
    mytable = Table('mytable', meta,
 
211
 
 
212
        # per-column CHECK constraint
 
213
        Column('col1', Integer, CheckConstraint('col1>5')),
 
214
 
 
215
        Column('col2', Integer),
 
216
        Column('col3', Integer),
 
217
 
 
218
        # table level CHECK constraint.  'name' is optional.
 
219
        CheckConstraint('col2 > col3 + 5', name='check1')
 
220
        )
 
221
 
 
222
    {sql}mytable.create(engine)
 
223
    CREATE TABLE mytable (
 
224
        col1 INTEGER  CHECK (col1>5),
 
225
        col2 INTEGER,
 
226
        col3 INTEGER,
 
227
        CONSTRAINT check1  CHECK (col2 > col3 + 5)
 
228
    ){stop}
 
229
 
 
230
Setting up Constraints when using the Declarative ORM Extension
 
231
----------------------------------------------------------------
 
232
 
 
233
The :class:`.Table` is the SQLAlchemy Core construct that allows one to define
 
234
table metadata, which among other things can be used by the SQLAlchemy ORM
 
235
as a target to map a class.  The :ref:`Declarative <declarative_toplevel>`
 
236
extension allows the :class:`.Table` object to be created automatically, given
 
237
the contents of the table primarily as a mapping of :class:`.Column` objects.
 
238
 
 
239
To apply table-level constraint objects such as :class:`.ForeignKeyConstraint`
 
240
to a table defined using Declarative, use the ``__table_args__`` attribute,
 
241
described at :ref:`declarative_table_args`.
 
242
 
 
243
Constraints API
 
244
---------------
 
245
.. autoclass:: Constraint
 
246
 
 
247
 
 
248
.. autoclass:: CheckConstraint
 
249
 
 
250
 
 
251
.. autoclass:: ColumnCollectionConstraint
 
252
 
 
253
 
 
254
.. autoclass:: ForeignKey
 
255
    :members:
 
256
 
 
257
 
 
258
.. autoclass:: ForeignKeyConstraint
 
259
    :members:
 
260
 
 
261
 
 
262
.. autoclass:: PrimaryKeyConstraint
 
263
 
 
264
 
 
265
.. autoclass:: UniqueConstraint
 
266
 
 
267
 
 
268
.. _schema_indexes:
 
269
 
 
270
Indexes
 
271
-------
 
272
 
 
273
Indexes can be created anonymously (using an auto-generated name ``ix_<column
 
274
label>``) for a single column using the inline ``index`` keyword on
 
275
:class:`~sqlalchemy.schema.Column`, which also modifies the usage of
 
276
``unique`` to apply the uniqueness to the index itself, instead of adding a
 
277
separate UNIQUE constraint. For indexes with specific names or which encompass
 
278
more than one column, use the :class:`~sqlalchemy.schema.Index` construct,
 
279
which requires a name.
 
280
 
 
281
Below we illustrate a :class:`~sqlalchemy.schema.Table` with several
 
282
:class:`~sqlalchemy.schema.Index` objects associated. The DDL for "CREATE
 
283
INDEX" is issued right after the create statements for the table:
 
284
 
 
285
.. sourcecode:: python+sql
 
286
 
 
287
    meta = MetaData()
 
288
    mytable = Table('mytable', meta,
 
289
        # an indexed column, with index "ix_mytable_col1"
 
290
        Column('col1', Integer, index=True),
 
291
 
 
292
        # a uniquely indexed column with index "ix_mytable_col2"
 
293
        Column('col2', Integer, index=True, unique=True),
 
294
 
 
295
        Column('col3', Integer),
 
296
        Column('col4', Integer),
 
297
 
 
298
        Column('col5', Integer),
 
299
        Column('col6', Integer),
 
300
        )
 
301
 
 
302
    # place an index on col3, col4
 
303
    Index('idx_col34', mytable.c.col3, mytable.c.col4)
 
304
 
 
305
    # place a unique index on col5, col6
 
306
    Index('myindex', mytable.c.col5, mytable.c.col6, unique=True)
 
307
 
 
308
    {sql}mytable.create(engine)
 
309
    CREATE TABLE mytable (
 
310
        col1 INTEGER,
 
311
        col2 INTEGER,
 
312
        col3 INTEGER,
 
313
        col4 INTEGER,
 
314
        col5 INTEGER,
 
315
        col6 INTEGER
 
316
    )
 
317
    CREATE INDEX ix_mytable_col1 ON mytable (col1)
 
318
    CREATE UNIQUE INDEX ix_mytable_col2 ON mytable (col2)
 
319
    CREATE UNIQUE INDEX myindex ON mytable (col5, col6)
 
320
    CREATE INDEX idx_col34 ON mytable (col3, col4){stop}
 
321
 
 
322
Note in the example above, the :class:`.Index` construct is created
 
323
externally to the table which it corresponds, using :class:`.Column`
 
324
objects directly.  :class:`.Index` also supports
 
325
"inline" definition inside the :class:`.Table`, using string names to
 
326
identify columns::
 
327
 
 
328
    meta = MetaData()
 
329
    mytable = Table('mytable', meta,
 
330
        Column('col1', Integer),
 
331
 
 
332
        Column('col2', Integer),
 
333
 
 
334
        Column('col3', Integer),
 
335
        Column('col4', Integer),
 
336
 
 
337
        # place an index on col1, col2
 
338
        Index('idx_col12', 'col1', 'col2'),
 
339
 
 
340
        # place a unique index on col3, col4
 
341
        Index('idx_col34', 'col3', 'col4', unique=True)
 
342
    )
 
343
 
 
344
.. versionadded:: 0.7
 
345
    Support of "inline" definition inside the :class:`.Table`
 
346
    for :class:`.Index`\ .
 
347
 
 
348
The :class:`~sqlalchemy.schema.Index` object also supports its own ``create()`` method:
 
349
 
 
350
.. sourcecode:: python+sql
 
351
 
 
352
    i = Index('someindex', mytable.c.col5)
 
353
    {sql}i.create(engine)
 
354
    CREATE INDEX someindex ON mytable (col5){stop}
 
355
 
 
356
.. _schema_indexes_functional:
 
357
 
 
358
Functional Indexes
 
359
~~~~~~~~~~~~~~~~~~~
 
360
 
 
361
:class:`.Index` supports SQL and function expressions, as supported by the
 
362
target backend.  To create an index against a column using a descending
 
363
value, the :meth:`.ColumnElement.desc` modifier may be used::
 
364
 
 
365
    from sqlalchemy import Index
 
366
 
 
367
    Index('someindex', mytable.c.somecol.desc())
 
368
 
 
369
Or with a backend that supports functional indexes such as Postgresql,
 
370
a "case insensitive" index can be created using the ``lower()`` function::
 
371
 
 
372
    from sqlalchemy import func, Index
 
373
 
 
374
    Index('someindex', func.lower(mytable.c.somecol))
 
375
 
 
376
.. versionadded:: 0.8 :class:`.Index` supports SQL expressions and functions
 
377
   as well as plain columns.
 
378
 
 
379
Index API
 
380
---------
 
381
 
 
382
.. autoclass:: Index
 
383
    :members: