You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

700 lines
46 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>pattern-db</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link type="text/css" rel="stylesheet" href="../clips.css" />
<style>
/* Small fixes because we omit the online layout.css. */
h3 { line-height: 1.3em; }
#page { margin-left: auto; margin-right: auto; }
#header, #header-inner { height: 175px; }
#header { border-bottom: 1px solid #C6D4DD; }
table { border-collapse: collapse; }
#checksum { display: none; }
</style>
<link href="../js/shCore.css" rel="stylesheet" type="text/css" />
<link href="../js/shThemeDefault.css" rel="stylesheet" type="text/css" />
<script language="javascript" src="../js/shCore.js"></script>
<script language="javascript" src="../js/shBrushXml.js"></script>
<script language="javascript" src="../js/shBrushJScript.js"></script>
<script language="javascript" src="../js/shBrushPython.js"></script>
</head>
<body class="node-type-page one-sidebar sidebar-right section-pages">
<div id="page">
<div id="page-inner">
<div id="header"><div id="header-inner"></div></div>
<div id="content">
<div id="content-inner">
<div class="node node-type-page"
<div class="node-inner">
<div class="breadcrumb">View online at: <a href="http://www.clips.ua.ac.be/pages/pattern-db" class="noexternal" target="_blank">http://www.clips.ua.ac.be/pages/pattern-db</a></div>
<h1>pattern.db</h1>
<!-- Parsed from the online documentation. -->
<div id="node-1432" class="node node-type-page"><div class="node-inner">
<div class="content">
<p class="big">The pattern.db module contains wrappers for databases (SQLite, MySQL), Unicode CSV files and Python's datetime. It offers a convenient way to work with tabular data, for example retrieved with the pattern.web module.</p>
<p>It can be used by itself or with other <a href="pattern.html">pattern</a> modules: <a href="pattern-web.html">web</a> | db | <a href="pattern-en.html">en</a> | <a href="pattern-search.html">search</a> <span class="blue"></span> | <a href="pattern-vector.html">vector</a> | <a href="pattern-graph.html">graph</a>.</p>
<p><img src="../g/pattern_schema.gif" alt="" width="620" height="180" /></p>
<hr />
<h2>Documentation</h2>
<ul style="margin-top: 0;">
<li><a href="#database">Database</a> <span class="smallcaps link-maintenance">(sqlite + mysql)</span></li>
<li><a href="#table">Table</a></li>
<li><a href="#query">Query</a></li>
<li><a href="#datasheet">Datasheet</a> <span class="smallcaps link-maintenance">(<a href="#csv">csv</a>)</span></li>
<li><a href="#date">Date</a></li>
</ul>
<p>&nbsp;</p>
<hr />
<h2><a name="database"></a>Database</h2>
<p>A database is a collection of tables. A table has rows of data with a specific data type (e.g., string, float) for each field or column. A database engine provides an interface to the database, using <a href="https://en.wikipedia.org/wiki/SQL" target="_blank">SQL</a> statements (Structured Query Language). Python 2.5+ comes bundled with the SQLite engine. The <a href="http://www.mysql.com/" target="_blank">MySQL</a> engine requires the <a href="http://sourceforge.net/projects/mysql-python/" target="_blank">MySQL-Python</a> bindings. Note that a 32-bit Python requires a 32-bit MySQL.</p>
<p>The <span class="inline_code">Database()</span> constructor creates (if necessary) and returns an <span class="inline_code">SQLITE</span> or <span class="inline_code">MYSQL</span> database. With <span class="inline_code">SQLITE</span>, it will create a file with the given name in the current folder.</p>
<pre class="brush:python; gutter:false; light:true;">db = Database(
name,
host = 'localhost',
port = 3306,
username = 'root',
password = '',
type = SQLITE
)
</pre><pre class="brush:python; gutter:false; light:true;">db.type # SQLITE | MYSQL
db.name # Database name.
db.host # Database host (MySQL).
db.port # Database port (MySQL).
db.username # Database username (MySQL).
db.password # Database password (MySQL).
db.tables # Dictionary of (name, Table)-items.
db.relations # List of relations, see Database.link().
db.query # Last executed SQL query.
db.connected # True after Database.connect(). </pre><pre class="brush:python; gutter:false; light:true;">db.connect() # Happens automatically.
db.disconnect()</pre><pre class="brush:python; gutter:false; light:true;">db.create(table, fields=[])
db.remove(table)
db.link(table1, field1, table2, field2, join=LEFT) </pre><pre class="brush:python; gutter:false; light:true;">db.execute(SQL, commit=False)
db.commit()
db.escape(value) # "a cat's tail" =&gt; "'a cat\'s tail'"</pre><ul>
<li><span class="inline_code">Database.execute()</span> returns an iterator of rows for the given SQL query.</li>
<li><span class="inline_code">Database.commit()</span> commits the changes of pending <span class="inline_code">INSERT</span>, <span class="inline_code">UPDATE</span>, <span class="inline_code">DELETE</span> queries.</li>
<li><span class="inline_code">Database.escape()</span> safely quotes and escapes field values.</li>
</ul>
<h3>Create table</h3>
<p><span class="inline_code">Database.create()</span> creates a new table in the database, It takes a table name and a list of row fields, where each field is defined with the <span class="inline_code">field()</span> function. Each field has a <span class="inline_code">name</span> (a-z + underscores) and a <span class="inline_code">type</span>, with an optional <span class="inline_code">default</span> value for new rows. The <span class="inline_code">pk()</span> function can be used for primary keys.</p>
<pre class="brush:python; gutter:false; light:true;">field(name, type=STRING, default=None, index=False, optional=True)</pre><pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">pk(name='id') # field('id', INTEGER, index=PRIMARY, optional=False) </pre><table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Type</span></td>
<td><span class="smallcaps">Value</span></td>
<td><span class="smallcaps">Example</span></td>
</tr>
<tr>
<td><span class="inline_code">STRING</span></td>
<td><span class="inline_code">str</span>, <span class="inline_code">unicode</span> (1-255 characters)</td>
<td><span class="inline_code">u'Schrödinger'</span></td>
</tr>
<tr>
<td><span class="inline_code">INTEGER</span></td>
<td><span class="inline_code">int</span></td>
<td><span class="inline_code">42</span></td>
</tr>
<tr>
<td><span class="inline_code">FLOAT</span></td>
<td><span class="inline_code">float</span></td>
<td><span class="inline_code">3.14159</span></td>
</tr>
<tr>
<td><span class="inline_code">TEXT</span></td>
<td><span class="inline_code">str</span>, <span class="inline_code">unicode</span></td>
<td><span class="inline_code">open('file.txt').read() </span></td>
</tr>
<tr>
<td><span class="inline_code">BLOB</span></td>
<td><span class="inline_code">str</span> (binary, e.g., PDF, PNG)</td>
<td><span class="inline_code">db.binary(open('img.jpg',</span> <span class="inline_code">'rb').read())</span></td>
</tr>
<tr>
<td><span class="inline_code">BOOLEAN</span></td>
<td><span class="inline_code">bool</span></td>
<td><span class="inline_code">True</span>, <span class="inline_code">False</span></td>
</tr>
<tr>
<td><span class="inline_code">DATE</span></td>
<td><span class="inline_code">Date</span></td>
<td><span class="inline_code">date('1999-12-31 23:59:59')</span></td>
</tr>
</tbody>
</table>
<p>A <span class="inline_code">STRING</span> field can contain up to a 100 characters. The length (1-255) can be changed by calling <span class="inline_code">STRING</span> as a function, e.g., <span class="inline_code">type=STRING(255)</span>. For longer strings, use <span class="inline_code">TEXT</span>. The default value for a <span class="inline_code">DATE</span> field is <span class="inline_code">NOW</span>.</p>
<p>With <span class="inline_code">index=True</span>, the field is indexed for faster search. The index can also be set to <span class="inline_code">UNIQUE</span> (no duplicates) or <span class="inline_code">PRIMARY</span>. A table must have a primary key field that uniquely identifies each row (i.e., an id). Integer primary keys are auto-numbered, there is no need to set the value manually in new rows.</p>
<p>With <span class="inline_code">optional=True</span>, the field is allowed to contain <span class="inline_code">None</span>.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Database, field, pk, STRING, BOOLEAN, DATE, NOW
&gt;&gt;&gt;
&gt;&gt;&gt; db = Database('my_stuff')
&gt;&gt;&gt; db.create('pets', fields=(
&gt;&gt;&gt; pk(),
&gt;&gt;&gt; field('name', STRING(80), index=True),
&gt;&gt;&gt; field('type', STRING(20)),
&gt;&gt;&gt; field('tail', BOOLEAN),
&gt;&gt;&gt; field('date_birth', DATE, default=None),
&gt;&gt;&gt; field('date_created', DATE, default=NOW)
&gt;&gt;&gt; ))</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.append(name=u'Schrödinger', type='cat', tail=True)
&gt;&gt;&gt; print db.pets.rows()[0]
(1, u'Schrödinger', u'cat', True, None, Date('2013-12-11 10:09:08'))</pre></div>
<h3>Create table from XML</h3>
<p><span class="inline_code">Database.create()</span> can also take a <span class="inline_code">Table.xml</span> or <span class="inline_code">Query.xml</span>. It creates a new table and copies the row data in the given XML string. An optional <span class="inline_code">name</span> parameter can be used to rename the new table. In <span class="inline_code">Query.xml</span>, a field name may contain a period. It will be replaced with an underscore (e.g., pets.name → pets_name). Alternatively, an alias can be defined in the <span class="inline_code">Query.aliases</span> dictionary.</p>
<p>&nbsp;</p>
<hr />
<h2><a name="table"></a>Table</h2>
<p>A <span class="inline_code">Table</span> is a list of rows, with one or more fields (i.e., table columns) of a certain type (i.e., string or number). A new table can be created with <span class="inline_code">Database.create()</span>. A <span class="inline_code">TableError</span> is raised if a table with the given name exists. An existing table can be retrieved with <span class="inline_code">Database.tables[name]</span>, <span class="inline_code">Database[name]</span> or <span class="inline_code">Database.&lt;name&gt;</span>.</p>
<pre class="brush:python; gutter:false; light:true;">table = Database.tables[name]</pre><pre class="brush:python; gutter:false; light:true;">table.db # Parent Database.
table.name # Table name (a-z + underscores).
table.fields # List of field names (i.e., columns).
table.schema # Dictionary of (field, Schema)-items.
table.default # Dictionary of (field, value)-items for new rows.
table.pk # Primary key field name.</pre><pre class="brush:python; gutter:false; light:true;">table.count() # Total number of rows (len(table) also works).
table.rows() # List of rows, each a tuple of fields.
</pre><pre class="brush:python; gutter:false; light:true;">table.record(row) # Dictionary of (field, value)-items for given row.</pre><pre class="brush:python; gutter:false; light:true;">table.append(fields={}, commit=True)
table.update(id, fields={}, commit=True)
table.remove(id, commit=True)
</pre><pre class="brush:python; gutter:false; light:true;">table.filter(*args, **kwargs)
table.search(*args, **kwargs) </pre><pre class="brush:python; gutter:false; light:true;">table.xml # XML string with the table schema and rows.
table.datasheet # Datasheet object (see below).</pre><ul>
<li><span class="inline_code">Table.rows()</span> returns a list of all rows. To iterate rows memory-efficiently, use <span class="inline_code">iter(</span><span class="inline_code">Table)</span>.</li>
<li><span class="inline_code">Table.append()</span>, <span class="inline_code">update()</span> and <span class="inline_code">remove()</span> modify the table contents.<br />With <span class="inline_code">commit=False</span>, changes are only committed after <span class="inline_code">Database.commit()</span> (= faster in batch).</li>
<li><span class="inline_code">Table.filter()</span> returns a subset of rows with a subset of fields.<br />For example: <span class="inline_code">table.filter('name',</span> <span class="inline_code">type='cat')</span>.</li>
</ul>
<h3>Table schema</h3>
<p>The <span class="inline_code">Table.schema</span> dictionary contains field name → <span class="inline_code">Schema</span> items.</p>
<pre class="brush:python; gutter:false; light:true;">schema = Table.schema[fieldname]</pre><pre class="brush:python; gutter:false; light:true;">schema.name # Field name.
schema.type # STRING, INTEGER, FLOAT, TEXT, BLOB, BOOLEAN, DATE
schema.length # STRING field length.
schema.default # Default value.
schema.index # PRIMARY | UNIQUE | True | False
schema.optional # True or False. </pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Database
&gt;&gt;&gt;
&gt;&gt;&gt; db = Database('my_stuff')
&gt;&gt;&gt;
&gt;&gt;&gt; print db.pets.fields
&gt;&gt;&gt; print db.pets.schema['name'].type
&gt;&gt;&gt; print db.pets.schema['name'].length
['id', 'name', 'tail', 'date_birth', 'date_created']
STRING
80 </pre></div>
<h3>Append row</h3>
<p><span class="inline_code">Table.append()</span> adds a new row with the given field values. It returns the row id, if the table has a primary key generated with <span class="inline_code">pk()</span>. Field values can be given as optional parameters, a dictionary or a tuple. Field values for a <span class="inline_code">BLOB</span> field must be wrapped in <span class="inline_code">Database.binary()</span>.<span style="color: #333333; font-family: Inconsolata, 'Courier New', Courier, monospace; font-size: small;"></span></p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.append(name=u'Schrödinger', date_birth=date('2009-08-12'))</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.append({'name': u'Schrödinger', 'date_birth': date('2009-08-12')}) </pre></div>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; db.pets.append((u'Schrödinger', 'cat', True, date('2009-08-12')) # in-order</pre></div>
<h3>Update row</h3>
<p><span class="inline_code">Table.update()</span> updates values in the row with the given primary key. A batch of rows can be updated using a <a class="link-maintenance" href="#filter">filter</a>, or a chain of filters with <span class="inline_code">any()</span> or <span class="inline_code">all()</span>. In the last example, all rows with <span class="inline_code">type='cat'</span> will have their <span class="inline_code">tail</span> field set to <span class="inline_code">True</span>.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.update(1, type='cat') # set type='cat' in row with id=1.</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.update(1, {'type': 'cat'})</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.update(eq('type', 'cat'), tail=True) </pre></div>
<h3>Remove row</h3>
<p><span class="inline_code">Table.remove()</span> removes the row with the given primary key:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.remove(1)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.remove(ALL)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.remove(all(eq('type', 'cat'), lt(year('date_birth'), 1990, '&lt;')))</pre></div>
<p>The last example removes all rows that have <span class="inline_code">type='cat'</span> AND year of birth before 1990.</p>
<h3><span>Filter rows</span></h3>
<p><span class="inline_code">Table.filter()</span> returns a list of rows filtered by field value(s), where each row is a tuple of fields. The first parameter defines which fields to return. It can be a single field name, a list of field names or <span class="inline_code">ALL</span>. The following parameters are optional and define field constraints. They can also be given as a dictionary:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter('name') # all rows, name</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter(('id', 'name')) # all rows, name + id</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter(ALL, type='cat') # type='cat', all fields</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter(ALL, type=('cat', 'dog')) # type='cat' OR type='dog' </pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter(ALL, type='*at') # type='cat' OR 'hat' OR 'brat', ...</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter(ALL, type='cat', tail=True) # type='cat' AND tail=True </pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.pets.filter('id', {'type': 'cat', 'tail': True})
</pre></div>
<p>More complex queries can be constructed with a <span class="inline_code">Query</span>.</p>
<p>&nbsp;</p>
<hr />
<h2><a name="query"></a>Query</h2>
<p><span class="inline_code">Table.search()</span> returns a new <span class="inline_code">Query</span> with options for filtering, sorting and ordering rows by field value(s). It can include fields from other, related tables.</p>
<pre class="brush:python; gutter:false; light:true;">query = Table.search(
fields = ALL,
filters = [],
relations = [],
sort = None,
order = ASCENDING,
group = None,
function = FIRST,
range = None
)</pre><pre class="brush:python; gutter:false; light:true;">query.table # Parent Table.
query.fields # Field name, list of field names, or ALL.
query.aliases # Dictionary of (field name, alias)-items.
query.filters # List of filter() objects.
query.relations # List of rel() objects.
query.sort # Field name or list of field names.
query.order # ASCENDING | DESCENDING
query.group # Field name or list of field names.
query.function # FIRST, LAST, COUNT, MIN, MAX, SUM, AVG, CONCATENATE
query.range # (start, stop)-tuple, e.g. rows 11-20.</pre><pre class="brush:python; gutter:false; light:true;">query.sql() # SQL string, can be used with Database.execute().</pre><pre class="brush:python; gutter:false; light:true;">query.rows() # List of rows, each a tuple of fields.</pre><pre class="brush:python; gutter:false; light:true;">query.record(row) # Dictionary of (field, value)-items for given row.</pre><pre class="brush:python; gutter:false; light:true;">query.xml # XML string with the query schema and rows.</pre><p>To iterate rows memory-efficiently, use <span class="inline_code">iter(Query)</span> instead of <span class="inline_code">Query.rows()</span>.</p>
<h3><a name="filter"></a>Query filter</h3>
<p>The <span class="inline_code">filter()</span> function creates a field-value constraint that matches certain rows in a table. A list of filters can be passed to the <span class="inline_code">filters</span> parameter of a <span class="inline_code">Query</span>.</p>
<pre class="brush:python; gutter:false; light:true;">filter(field, value, comparison='=')</pre><table class="border">
<tbody>
<tr>
<td style="text-align: center;"><span class="smallcaps">Comparison</span></td>
<td><span class="smallcaps">Description</span></td>
<td><span class="smallcaps">Example</span></td>
<td style="text-align: center;"><span class="smallcaps">Alias</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">=</span></td>
<td>equal to</td>
<td><span class="inline_code">filter('type',</span> <span class="inline_code">('cat',</span> <span class="inline_code">'dog'),</span> <span class="inline_code">'=') </span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;eq()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">i=</span></td>
<td>equal to (case-insensitive)</td>
<td><span class="inline_code">filter('name',</span> <span class="inline_code">'tig*',</span> <span class="inline_code">'i=') </span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;eqi()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">!=</span></td>
<td>not equal to</td>
<td><span class="inline_code">filter('name',</span> <span class="inline_code">'*y',</span> <span class="inline_code">'!=')</span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;ne()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">&gt;</span></td>
<td>greater than</td>
<td><span class="inline_code">filter('weight',</span> <span class="inline_code">10,</span> <span class="inline_code">'&gt;') </span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;gt()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">&lt;</span></td>
<td>less than</td>
<td><span class="inline_code">filter('weight',</span> <span class="inline_code">10,</span> <span class="inline_code">'&lt;') </span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;lt()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">&gt;=</span></td>
<td>greater than or equal to</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">1999,</span> <span class="inline_code">'&gt;=') </span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;gte()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">&lt;=</span></td>
<td>less than or equal to</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">2002,</span> <span class="inline_code">'&lt;=')</span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;lte()</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="inline_code">:</span></td>
<td>between (inclusive)</td>
<td><span class="inline_code">filter(year('date'),</span> <span class="inline_code">(1999,</span> <span class="inline_code">2002),</span> <span class="inline_code">':')</span></td>
<td style="text-align: left;"><span class="inline_code">&nbsp;rng()</span></td>
</tr>
</tbody>
</table>
<p>The field name of a <span class="inline_code">DATE</span> field can be passed to the&nbsp;<span class="inline_code">year()</span>, <span class="inline_code">month()</span>, <span class="inline_code">day()</span>, <span class="inline_code">hour()</span>, <span class="inline_code">minute()</span> or <span class="inline_code">second()</span> function.The short aliases of <span class="inline_code">filter()</span> have a preset comparison operator.</p>
<h3>Query filter chain</h3>
<p>Filters can be chained together. The <span class="inline_code">all()</span> function returns a list with AND logic. The <span class="inline_code">any()</span> function returns a list with OR logic. In the example below, the first query matches <span style="text-decoration: underline;">all</span> cats named Taxi. The second and third query match <span style="text-decoration: underline;">any</span> pet that is cat OR that is named Taxi.</p>
<pre class="brush:python; gutter:false; light:true;">all(filter1, filter2, ...) # Rows must match ALL of the filters.</pre><pre class="brush:python; gutter:false; light:true;">any(filter1, filter2, ...) # Rows must match ANY of the filters.</pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Database, eq, all, any
&gt;&gt;&gt;
&gt;&gt;&gt; db = Database('my_stuff')
&gt;&gt;&gt;
&gt;&gt;&gt; db.pets.search(filters=all(eq('name', 'Taxi'), eq('type', 'cat')))
&gt;&gt;&gt; db.pets.search(filters=any(eq('name', 'Taxi'), eq('type', 'cat')))
&gt;&gt;&gt; db.pets.search(filters=any(name='Taxi', type='cat')) </pre></div>
<p>Lists created with <span class="inline_code">all()</span> and <span class="inline_code">any()</span> can be nested to define complex search criteria. The example below matches all pets that are cats, and whose name starts with Fluff- OR ends with a -y:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; f = any(eq('name', 'Fluff*'), eq('name', '*y')) # OR
&gt;&gt;&gt; f = all(eq('type', 'cat'), f) # AND
&gt;&gt;&gt;
&gt;&gt;&gt; for row in db.pets.search(filters=f):
&gt;&gt;&gt; print row</pre></div>
<p>The syntax can even be more concise:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; for row in db.pets.search(filters=all(name=('Fluff*', '*y'), type='cat')):
&gt;&gt;&gt; print row </pre></div>
<h3>Query relation</h3>
<p>The <span class="inline_code">rel()</span> function defines a relation between two fields in different tables (usually id's).</p>
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">rel(field1, field2, table, join=LEFT) # LEFT | INNER</pre><p>The optional <span class="inline_code">join</span> parameter defines how rows are matched. <span class="inline_code">LEFT</span> takes all rows from the base table, with additional fields from the related table. For a row with no match between <span class="inline_code">field1</span> and <span class="inline_code">field2</span>, these fields have value <span class="inline_code">None</span>. <span class="inline_code">INNER</span> takes the subset of rows that have a match between <span class="inline_code">field1</span> and <span class="inline_code">field2</span>.</p>
<p>A well-known example is a database app that processes invoices. Say we have a products table and an orders table. Each order has a product id instead of all product details. Each product id can occur in multiple orders. This approach is called database normalization. It avoids duplicate data. To generate an invoice, we can combine product details and order details using a query relation.</p>
<p>The following example demonstrates a simple products + customers + orders database app:</p>
<table class="border=">
<tbody>
<tr>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">products</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: left;"><span class="smallcaps">name</span></td>
<td style="text-align: center;"><span class="smallcaps">price</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: left;">pizza</td>
<td style="text-align: center;">15</td>
</tr>
<tr>
<td style="text-align: center;">2</td>
<td style="text-align: left;">garlic bread</td>
<td style="text-align: center;">3</td>
</tr>
</tbody>
</table>
</td>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">customers</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: left;"><span class="smallcaps">name</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: left;">Schrödinger</td>
</tr>
<tr>
<td style="text-align: center;">2</td>
<td style="text-align: left;">Hofstadter</td>
</tr>
</tbody>
</table>
</td>
<td>
<table class="border" style="margin: 0;">
<tbody>
<tr>
<td style="text-align: center;" colspan="3"><span class="smallcaps">orders</span></td>
</tr>
<tr>
<td style="text-align: center;"><span class="smallcaps">id</span></td>
<td style="text-align: center;"><span class="smallcaps">product</span></td>
<td style="text-align: center;"><span class="smallcaps">customer</span></td>
</tr>
<tr>
<td style="text-align: center;">1</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">2</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Database, field, pk, INTEGER as I
&gt;&gt;&gt;
&gt;&gt;&gt; db = Database('pizza_delivery')
&gt;&gt;&gt;
&gt;&gt;&gt; db.create( 'products', (pk(), field('name'), field('price', I)))
&gt;&gt;&gt; db.create('customers', (pk(), field('name')))
&gt;&gt;&gt; db.create( 'orders', (pk(), field('product', I), field('customer', I)))</pre></div>
<div class="example">Add products and customers. Pizza delivery is open for business!</div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.products.append(name='pizza', price=15)
&gt;&gt;&gt; db.products.append(name='garlic bread', price=3)</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.customers.append(name=u'Schrödinger')
&gt;&gt;&gt; db.customers.append(name=u'Hofstadter')</pre></div>
<p>Hofstadter orders a pizza.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; db.orders.append(product=1, customer=2)</pre></div>
<div class="example">An orders query with relations to products and customers generates a human-readable invoice:</div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Database, rel
&gt;&gt;&gt;
&gt;&gt;&gt; db = Database('pizza_delivery')
&gt;&gt;&gt;
&gt;&gt;&gt; f = ('orders.id', 'customers.name', 'products.name', 'products.price')
&gt;&gt;&gt; q = db.orders.search(f, relations=(
&gt;&gt;&gt; rel('orders.customer', 'customers.id', 'customers'),
&gt;&gt;&gt; rel('orders.product', 'products.id', 'products'))
&gt;&gt;&gt; )
&gt;&gt;&gt; for row in q:
&gt;&gt;&gt; print q.record(row)
{ 'orders.id' : 1,
'customers.name' : u'Hofstadter',
'products.name' : u'pizza',
'products.price' : 15 }</pre></div>
<div class="example">If a relation is used repeatedly, define it once with <span class="inline_code">Database.link()</span>. It will be available in every <span class="inline_code">Query</span>.</div>
<h3>Grouping rows</h3>
<p>A <span class="inline_code">Query</span> has an optional parameter <span class="inline_code">group</span> that can be used to merge rows on duplicate field values. The given <span class="inline_code">function</span> is applied to the other fields. It can also be a list with a function for each field.</p>
<table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Function</span></td>
<td style="text-align: center;"><span class="smallcaps">Field type</span></td>
<td><span class="smallcaps">Description</span></td>
</tr>
<tr>
<td><span class="inline_code">FIRST</span></td>
<td style="text-align: center;">any</td>
<td>The first row field in the group.</td>
</tr>
<tr>
<td><span class="inline_code">LAST</span></td>
<td style="text-align: center;">any</td>
<td>The last row field in the group.</td>
</tr>
<tr>
<td><span class="inline_code">COUNT</span></td>
<td style="text-align: center;">any</td>
<td>The number of rows in the group.</td>
</tr>
<tr>
<td><span class="inline_code">MIN</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The lowest field value in the group.</td>
</tr>
<tr>
<td><span class="inline_code">MAX</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The highest field value in the group.</td>
</tr>
<tr>
<td><span class="inline_code">SUM</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The sum of all field values in the group.</td>
</tr>
<tr>
<td><span class="inline_code">AVG</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The average of all field values in the group.</td>
</tr>
<tr>
<td><span class="inline_code">STDEV</span></td>
<td style="text-align: center;"><span class="inline_code">INTEGER</span> + <span class="inline_code">FLOAT</span></td>
<td>The standard deviation (= variation from average).</td>
</tr>
<tr>
<td><span class="inline_code">CONCATENATE</span></td>
<td style="text-align: center;"><span class="inline_code">STRING</span></td>
<td>Joins all field values with a comma.</td>
</tr>
</tbody>
</table>
<p>For example, to get the total revenue per ordered product:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; print db.orders.search(
&gt;&gt;&gt; fields = ('products.name', 'products.price'),
&gt;&gt;&gt; relations = rel('product', 'products.id', 'products'),
&gt;&gt;&gt; group = 'products.name', # Merge orders with same product name.
&gt;&gt;&gt; function = SUM # Sum of product prices.
&gt;&gt;&gt; ).rows()</pre></div>
<p>&nbsp;</p>
<hr />
<h2><a name="datasheet"></a>Datasheet</h2>
<p>A <span class="inline_code">Datasheet</span> is a matrix of rows and columns, where each row and column can be retrieved as a list. The data can be imported or exported as a CSV-file. Optionally, the given <span class="inline_code">fields</span> is a list of <span class="inline_code">(name,</span> <span class="inline_code">type)</span> headers, where <span class="inline_code">type</span> can be <span class="inline_code">STRING</span>, <span class="inline_code">TEXT</span>, <span class="inline_code">INTEGER</span>, <span class="inline_code">FLOAT</span>, <span class="inline_code">BOOLEAN</span>, <span class="inline_code">BLOB</span> or <span class="inline_code">DATE</span>.</p>
<pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet(rows=[], fields=None)</pre><pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet.load(path, separator=',', decoder=lambda v: v, headers=False)
</pre><pre class="brush:python; gutter:false; light:true;">datasheet.rows # List of rows (each row = list of values).
datasheet.columns # List of columns (each column = list of values).
datasheet.fields # List of (name, type) column headers.
datasheet.&lt;field&gt; # List of column values. </pre><pre class="brush:python; gutter:false; light:true;">datasheet[i] # Row at index i.
datasheet[i, j] # Value in row i at column j.
datasheet[i1:i2, j] # Slice of column j from rows i1-i2.
datasheet[i, j1:j2] # Slice of columns j1-j2 from row i.
datasheet[i1:i2, j1:j2] # Datasheet with columns j1-j2 from rows i1-i2.
datasheet[:] # Datasheet copy. </pre><pre class="brush:python; gutter:false; light:true;">datasheet.insert(i, row, default=None)
datasheet.append(row, default=None)
datasheet.extend(rows, default=None)
datasheet.copy(rows=ALL, columns=ALL)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.group(j, function=FIRST, key=lambda v: v)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.save(path, separator=',', encoder=lambda v: v, headers=False)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.json # JSON-formatted string.</pre><ul>
<li><span class="inline_code">Datasheet.insert()</span> and <span class="inline_code">append()</span> fill missing columns with the <span class="inline_code">default</span> value.</li>
<li><span class="inline_code">Datasheet.columns.insert()</span> and <span class="inline_code">append()</span> fill missing rows with the <span class="inline_code">default</span> value.<br />An optional <span class="inline_code">field</span> parameter can be used to supply a (<span class="inline_code">name</span>, <span class="inline_code">type</span>) column header.</li>
<li><span class="inline_code">Datasheet.copy()</span> returns a new <span class="inline_code">Datasheet</span> from a selective list of row and/or column indices.</li>
<li>To rotate a datasheet 90 degrees, use <span class="inline_code">datasheet</span> <span class="inline_code">=</span> <span class="inline_code">flip(datasheet)</span>.</li>
</ul>
<p>For example:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; from pattern.db import Datasheet
&gt;&gt;&gt;
&gt;&gt;&gt; ds = Datasheet()
&gt;&gt;&gt; ds.append((u'Schrödinger', 'cat'))
&gt;&gt;&gt; ds.append((u'Hofstadter', 'cat'))
&gt;&gt;&gt; ds.save('pets.csv')
&gt;&gt;&gt;
&gt;&gt;&gt; ds = Datasheet.load('pets.csv')
&gt;&gt;&gt; print ds
[[u'Schrödinger', 'cat'],
[ u'Hofstadter', 'cat']]</pre></div>
<h3>Grouping rows</h3>
<p><span class="inline_code">Datasheet.group(j)</span> returns a new <span class="inline_code">Datasheet</span> with unique values in column <span class="inline_code">j</span>. It merges rows using a given <span class="inline_code">function</span> that takes a list of column values and returns a single value. Predefined functions are <span class="inline_code">FIRST</span>, <span class="inline_code">LAST</span>, <span class="inline_code">COUNT</span>, <span class="inline_code">MIN</span>, <span class="inline_code">MAX</span>, <span class="inline_code">SUM</span>, <span class="inline_code">AVG</span>, <span class="inline_code">STDEV</span> and <span class="inline_code">CONCATENATE</span>. It can also be a list of functions.</p>
<p>The optional <span class="inline_code">key</span> can be used to compare the values in column <span class="inline_code">j</span>. For example, <span class="inline_code">lambda</span> <span class="inline_code">date:</span> <span class="inline_code">date.year</span> groups a column of <span class="inline_code">Date</span> objects by year.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Datasheet, pprint
&gt;&gt;&gt;
&gt;&gt;&gt; ds = Datasheet(rows=[
&gt;&gt;&gt; (1, u'Schrödinger', 'cat'),
&gt;&gt;&gt; (2, u'Hofstadter', 'cat'),
&gt;&gt;&gt; (3, u'Taxi', 'dog')
&gt;&gt;&gt; ])
&gt;&gt;&gt;
&gt;&gt;&gt; g = ds.copy(columns=[2, 0]) # A copy with type &amp; id.
&gt;&gt;&gt; g = g.group(0, COUNT) # Group type, count rows per type.
&gt;&gt;&gt; pprint(g, fill='')
cat 2
dog 1 </pre></div>
<h3>Sorting rows &amp; columns</h3>
<p><span class="inline_code">Datasheet.columns[j].sort()</span> sorts the rows according to the values in column <span class="inline_code">j</span>. <br /><span class="inline_code">Datasheet.columns.sort()</span> can be used to change the column order:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; ds.columns.sort(order=[0, 2, 1])
&gt;&gt;&gt; pprint(ds, fill='')
1 cat Schrödinger
2 cat Hofstadter
3 dog Taxi</pre></div>
<p><span class="inline_code">Datasheet.columns.swap(j1,j2)</span> swaps two individual columns with given indices.</p>
<h3><a name="csv"></a>CSV import &amp; export</h3>
<p><span class="inline_code">Datasheet.save()</span> exports the matrix as a CSV file. <span class="inline_code">Datasheet.load()</span> returns a <span class="inline_code">Datasheet</span> from a given CSV file. CSV (comma-separated values) is a simple text format for tabular data, where each line is a row and each value is separated by a comma.</p>
<pre class="brush:python; gutter:false; light:true;">datasheet = Datasheet.load(path, separator=',', decoder=lambda v: v, headers=False)</pre><pre class="brush:python; gutter:false; light:true;">datasheet.save(path, separator=',', encoder=lambda v: v, headers=False)</pre><p>On export, all&nbsp;<span class="inline_code">str</span>, <span class="inline_code">int</span>, <span class="inline_code">float</span>, <span class="inline_code">bool</span> and <span class="inline_code">Date</span> values are converted to Unicode. An <span class="inline_code">encoder</span> can be given for other data types. On import, all values in the datasheet will be Unicode unless a <span class="inline_code">decoder</span> is given.</p>
<p>With <span class="inline_code">headers=True</span>, the <span class="inline_code">Datasheet.fields</span> headers are exported and imported (first line in CSV). In this case, the data type for each column (<span class="inline_code">STRING</span>, <span class="inline_code">INTEGER</span>, <span class="inline_code">FLOAT</span>, <span class="inline_code">BOOLEAN</span> or <span class="inline_code">DATE</span>) is explicitly known and no <span class="inline_code">encoder</span> or <span class="inline_code">decoder</span> is needed.</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import Datasheet, STRING, DATE, date
&gt;&gt;&gt;
&gt;&gt;&gt; ds = Datasheet(fields=(('name', STRING), ('date', DATE)))
&gt;&gt;&gt; ds.append((u'Schrödinger', date('1887-08-12')))
&gt;&gt;&gt; ds.append((u'Hofstadter', date('1945-02-15')))
&gt;&gt;&gt;
&gt;&gt;&gt; ds.save('pets.csv', headers=True)
&gt;&gt;&gt;
&gt;&gt;&gt; ds = Datasheet.load('pets.csv', headers=True)
&gt;&gt;&gt; print ds[0]
[u'Schrödinger', Date('1887-08-12 00:00:00')]
</pre></div>
<p>The <span class="inline_code">csv()</span> function can also be used instead of <span class="inline_code">Datasheet.load()</span>:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; from pattern.db import csv
&gt;&gt;&gt;
&gt;&gt;&gt; for name, date in csv('pets.csv', separator=',', headers=True):
&gt;&gt;&gt; print name, date</pre></div>
<p>&nbsp;</p>
<hr />
<h2><a name="date"></a>Date</h2>
<p>The <span class="inline_code">date()</span> function returns a new <span class="inline_code">Date</span>, a convenient subclass of Python's <span class="inline_code">datetime.datetime</span>. It takes an integer (Unix timestamp), a string or <span class="inline_code">NOW</span>. An optional string input format and output format can be given (e.g., <span class="inline_code">"%d/%m/%y"</span>). The default output format is <span class="inline_code">"YYYY-MM-DD hh:mm:ss"</span>.</p>
<pre class="brush:python; gutter:false; light:true;">d = date(int)</pre><pre class="brush:python; gutter:false; light:true;">d = date(NOW, format=DEFAULT)
</pre><pre class="brush:python; gutter:false; light:true;">d = date(string)</pre><pre class="brush:python; gutter:false; light:true;">d = date(string, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(string, inputformat, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(year, month, day, format=DEFAULT)</pre><pre class="brush:python; gutter:false; light:true;">d = date(year, month, day, hours, minutes, seconds, format=DEFAULT)</pre><pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">d.year
d.month # 1-12
d.week # 1-52
d.weekday # 1-7
d.day # 1-31
d.minute # 1-60
d.second # 1-60
d.timestamp # Seconds elapsed since 1/1/1970.</pre><p>If no string input format is given, a number of common formats will be tried:</p>
<table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Format</span></td>
<td><span class="smallcaps">Example</span></td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d %H:%M:%S</span></td>
<td>2010-09-21 09:27:01</td>
</tr>
<tr>
<td><span class="inline_code">%a, %d %b %Y %H:%M:%S %z</span></td>
<td>Tue, 9 Sep 2010 17:58:28 +0000</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%dT%H:%M:%SZ</span></td>
<td>2010-09-20T09:27:01Z</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%dT%H:%M:%S+0000</span></td>
<td>2010-09-20T09:27:01+0000</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d %H:%M</span></td>
<td>2010-09-20 09:27</td>
</tr>
<tr>
<td><span class="inline_code">%Y-%m-%d</span></td>
<td>2010-09-20</td>
</tr>
<tr>
<td><span class="inline_code">%d/%m/%Y</span></td>
<td>20/09/2010</td>
</tr>
<tr>
<td><span class="inline_code">%d %B %Y</span></td>
<td>9 september 2010</td>
</tr>
<tr>
<td><span class="inline_code">%B %d %Y</span></td>
<td>September 9 2010</td>
</tr>
<tr>
<td><span class="inline_code">%B %d, %Y</span></td>
<td>September 09, 2010</td>
</tr>
</tbody>
</table>
<p>All date formats used in <a class="link-maintenance" href="pattern-web.html">pattern.web</a> (e.g., Twitter search result) are automatically detected.<br />For an overview of date format syntax, see: <a href="http://docs.python.org/library/time.html#time.strftime" target="_blank">http://docs.python.org/library/time.html#time.strftime</a>.<br />&nbsp;</p>
<p><span class="smallcaps">Date calculations</span></p>
<p>The <span class="inline_code">time()</span> function can be used to add or subtract time to a <span class="inline_code">Date</span>:</p>
<pre class="brush:python; gutter:false; light:true;">time(days=0, seconds=0, minutes=0, hours=0)</pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.db import date, time
&gt;&gt;&gt;
&gt;&gt;&gt; d = date('23 august 2011')
&gt;&gt;&gt; d += time(days=2, hours=5)
&gt;&gt;&gt; print type(d)
&gt;&gt;&gt; print d
&gt;&gt;&gt; print d.year, d.month, d.day
&lt;class 'pattern.db.Date'&gt;
2011-08-25 05:00:00
2011, 8, 25 </pre></div>
<p>&nbsp;</p>
<hr />
<h2>See also</h2>
<ul>
<li><a href="http://www.cherrypy.org/" target="_blank">CherryPy</a> (BSD): o<span>bject-oriented HTTP framework for Python.</span></li>
<li><span><a href="https://www.djangoproject.com/" target="_blank">Django</a> (BSD): m</span><span>odel-view-controller framework for Python.</span></li>
</ul>
</div>
</div></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
SyntaxHighlighter.all();
</script>
</body>
</html>