select

□未翻訳

□翻訳中

■翻訳完了(細田謙二)

■レビュー(Omi Chiba)

select

Set、sが与えられると、selectコマンドを用いてレコードを取得することができます:

Given a Set, s, you can fetch the records with the command select:

1.

>>> rows = s.select()

これは、Rowオブジェクトを要素とするgluon.sql.Rowsクラスの反復可能なオブジェクトを返します。gluon.sql.Rowオブジェクトは辞書のように振舞いますが、gluon.storage.Storageと同様、その要素は属性に関連付けられています。前者は、その値が読み取り専用であるということで後者とは異なります。

It returns an iterable object of class gluon.sql.Rows whose elements are Row objects.gluon.sql.Row objects act like dictionaries, but their elements can also be accessed as attributes, like gluon.storage.Storage.The former differ from the latter because its values are readonly.

Rowsオブジェクトは、選択の結果に対しループを回して、各行の選択したフィールドをプリントできるようにすることができます:

The Rows object allows looping over the result of the select and printing the selected field values for each row:

1.

2.

3.

>>> for row in rows:

print row.id, row.name

1 Alex

上の一連の手順は、次のように1つの文で行うことができます:

You can do all the steps in one statement:

1.

2.

3.

>>> for row in db(db.person.name=='Alex').select():

print row.name

Alex

selectコマンドは引数をとることが可能です。すべての無名引数は、取得したいフィールド名として解釈されます。たとえば、"id"と"name"フィールドを明示的に取得することができます:

The select command can take arguments. All unnamed arguments are interpreted as the names of the fields that you want to fetch. For example, you can be explicit on fetching field "id" and field "name":

1.

2.

3.

4.

5.

>>> for row in db().select(db.person.id, db.person.name):

print row.name

Alex

Bob

Carl

テーブルのALL属性によって、すべてのフィールドを指定することができます:

The table attribute ALL allows you to specify all fields:

1.

2.

3.

4.

5.

>>> for row in db().select(db.person.ALL):

print row.name

Alex

Bob

Carl

dbにはクエリ文字列が何も渡されていないことに注目してください。web2pyは、personテーブルのすべてのフィールドが追加情報なしに要求された場合、personテーブルのすべてのレコードが要求されていることを理解します。

Notice that there is no query string passed to db. web2py understands that if you want all fields of the table person without additional information then you want all records of the table person.

同等の代替構文は以下の通りです:

An equivalent alternative syntax is the following:

1.

2.

3.

4.

5.

>>> for row in db(db.person.id > 0).select():

print row.name

Alex

Bob

Carl

person(id>0)テーブルのすべてのレコードが追加情報なしに要求された場合、web2pyはpersonテーブルのすべてのフィールドが要求されていることを理解します。

and web2py understands that if you ask for all records of the table person (id > 0) without additional information, then you want all the fields of table person.

ショートカット

Shortcuts

DALはコードを簡素化するさまざまなショートカットをサポートしています。具体例を示します:

The DAL supports various code-simplifying shortcuts. In particular:

1.

myrecord = db.mytable[id]

これは、与えられたidを持つレコードを、それが存在すれば返します。そのidが存在しない場合は、Noneを返します。上記の文は以下と等価です:

returns the record with the given id if it exists. If the id does not exist, it returns None. The above statement is equivalent to

1.

myrecord = db(db.mytable.id==id).select().first()

次のようにして、idでレコードを削除することができます:

You can delete records by id:

1.

del db.mytable[id]

これは以下と等価です

and this is equivalent to

1.

db(db.mytable.id==id).delete()

これは、与えられたidを持つレコードを、それが存在すれば削除します。

and deletes the record with the given id, if it exists.

次のようにして、レコードを挿入することが可能です:

You can insert records:

1.

db.mytable[0] = dict(myfield='somevalue')

これは以下と等価です

It is equivalent to

1.

db.mytable.insert(myfield='somevalue')

これは、右側の辞書で指定されたフィールド値を持つ新規レコードを作成します。

and it creates a new record with field values specified by the dictionary on the right hand side.

次のようにしてレコードを更新することができます:

You can update records:

1.

db.mytable[id] = dict(myfield='somevalue')

これは以下と等価です

which is equivalent to

1.

db(db.mytable.id==id).update(myfield='somevalue')

これは、右側の辞書で指定されたフィールド値で既存のレコードを更新します。

and it updates an existing record with field values specified by the dictionary on the right hand side.

Rowの取り出し

Fetching a Row

さらにもう1つの便利な構文は以下の通りです:

Yet another convenient syntax is the following:

1.

2.

3.

record = db.mytable(id)

record = db.mytable(db.mytable.id==id)

record = db.mytable(id,myfield='somevalue')

上記の構文は、明らかにdb.mytable[id]と似ていますが、より柔軟性が高く、安全です。まず初めに、これはidがint(またはstr(id)がint)であることを確認し、そうでない場合はNoneを返します(例外を発生させることはありません)。レコードが満たす必要のある複数の条件を指定することも可能です。条件に合わない場合は、またNoneを返します。

Apparently similar to db.mytable[id] the above syntax is more flexible and safer. First of all it checks whether id is an int (or str(id) is an int) and returns None if not (it never raises an exception). It also allows to specify multiple conditions that the record must meet. If they are not met, it also returns None.

再帰的なselect

Recursive selects

前述のpersonテーブルと、"person"を参照する新規の"dog"テーブルを考えます:

Consider the previous table person and a new table "dog" referencing a "person":

1.

>>> db.define_table('dog', Field('name'), Field('owner',db.person))

このテーブルからの単純な選択は次のようになります:

and a simple select from this table:

1.

>>> dogs = db(db.dog.id>0).select()

dogsの各Rowに対して、選択したテーブル(dog)からのフィールドだけでなく、リンクしたテーブルからのフィールド(再帰的に)取り出すことが可能です:

For each Row of dogs it is possible to fetch not just fields from the selected table (dog) but also from linked tables (recursively):

1.

>>> for dog in dogs: print dog.name, dog.owner.name

ここでは、dog.owner.nameは、dogsの各dogに対して、1回のデータベースの選択を要求するので、非効率です。利用できるときは、再帰的な選択の代わりにjoinを用いることを推奨します。とはいえ、これは個々のレコードにアクセスするときに便利で実用的です。

Here dog.owner.name requires one database select for each dog in dogs and it is therefore inefficient. We suggest using joins whenever possible instead of recursive selects, nevertheless this is convenient and practical when accessing individual records.

あるpersonによって参照されたdogsを選択して、これを逆方向で行うことも可能です:

You can also do it backwards, by selecting the dogs referenced by a person:

1.

2.

3.

person = db.person(id)

for dog in person.dog.select(orderby=db.dog.name):

print person.name, 'owns', dog.name

この最後の式において、person.dogは次のものに対するショートカットになります:

In this last expressions person.dog is a shortcut for

1.

db(db.dog.owner==person.id)

つまり、現在のpersonによって参照されたdogsのSetになります。この構文は、参照しているテーブルが参照されたテーブルへ複数の参照を持つ場合は、破綻します。この場合、より明示的にして、完全なクエリを使用する必要があります。

i.e. the Set of dogs referenced by the current person. This syntax breaks down if the referencing table has multiple references to the referenced table. In this case one needs to be more explicit and use a full Query.

ビューにおけるRowsのシリアライズ

Serializing Rows in Views

selectの結果は、次の構文を使用してビューに表示することができます:

The result of a select can be displayed in a view with the following syntax:

1.

2.

3.

{{extend 'layout.html'}}

<h1>Records</h2>

{{=db().select(db.person.ALL)}}

これは、HTMLのテーブルへと自動的に変換されます。テーブルは、ヘッダにカラム名を持ち、各行に各レコードを持っています。行は"even"と"odd"クラスで交互にマークされます。内部では、Rowsは最初にSQLTABLEオブジェクト(テーブルとは混同しないでください)へと変換され、シリアライズされます。データベースから抽出した値はまた、そのフィールドに関連付けられたバリデータによって書式化され、エスケープされます。(注:ビュー内でdbをこのような方法で用いることは、普通は、良いMVCのプラクティスとして考えられていません。)

and it is automatically converted into an HTML table with a header containing the column names and one row per record. The rows are marked as alternating class "even" and class "odd". Under the hood, the Rows is first converted into a SQLTABLE object (not to be confused with Table) and then serialized. The values extracted from the database are also formatted by the validators associated to the field and then escaped. (Note: Using a db in this way in a view is usually not considered good MVC practice.)

また、SQLTABLEを明示的に呼び出すことは可能で、便利なときがあります。

Yet it is possible and sometimes convenient to call SQLTABLE explicitly.

SQLTABLEのコンストラクタは次のようなオプション的引数をとります:

The SQLTABLE constructor takes the following optional arguments:

  • linkto URLまたは参照フィールドへリンクするために使用されるアクション(デフォルトはNone)

  • the URL or an action to be used to link reference fields (default to None)

  • upload URLまたはアップロードしたファイルのダウンロードを可能にするダウンロードアクション(デフォルトはNone)

  • the URL or the download action to allow downloading of uploaded files (default to None)

  • headers フィールド名とヘッダとして用いるそのラベルをマッピングする辞書(デフォルトは{})。一種の命令をすることもできます。現在は、headers='fieldname:capitalize'をサポートしています。

  • a dictionary mapping field names to their labels to be used as headers (default to {}). It can also be an instruction. Currently we supportheaders='fieldname:capitalize'.

  • truncate テーブル内の長い値を切り捨てるための文字数(デフォルトは16)

  • the number of characters for truncating long values in the table (default is 16)

  • columns カラムとして表示するフィールド名のリスト(tablename.fieldnameのフォーマット)。リストされていないものは表示されません(デフォルトはすべてです)。

  • the list of fieldnames to be shown as columns (in tablename.fieldname format). Those not listed are not displayed (defaults to all).

  • **attributes 最外部のTABLEオブジェクトに渡される汎用的なヘルパ属性です。

  • generic helper attributes to be passed to the most external TABLE object.

以下が具体例です。

Here is an example:

1.

2.

3.

4.

5.

6.

7.

{{extend 'layout.html'}}

<h1>Records</h2>

{{=SQLTABLE(db().select(db.person.ALL),

headers='fieldname:capitalize',

truncate=100,

upload=URL('download'))

}}

orderby, groupby, limitby, distinct

selectコマンドは5つのオプション引数をとります:orderby、groupby、limitby、left、cacheです。ここでは、最初の3つについて説明します。

The select command takes five optional arguments: orderby, groupby, limitby, left and cache. Here we discuss the first three.

次のように、nameでソートされたレコードを取り出すことができます:

You can fetch the records sorted by name:

1.

2.

3.

4.

5.

6.

>>> for row in db().select(

db.person.ALL, orderby=db.person.name):

print row.name

Alex

Bob

Carl

nameの逆順でソートされたレコードを取り出すことができます(チルダに注意してください):

You can fetch the records sorted by name in reverse order (notice the tilde):

1.

2.

3.

4.

5.

6.

>>> for row in db().select(

db.person.ALL, orderby=~db.person.name):

print row.name

Carl

Bob

Alex

ランダムな順番で取り出したレコードを得ることが可能です:

You can have the fetched records appear in random order:

1.

2.

3.

4.

5.

6.

>>> for row in db().select(

db.person.ALL, orderby='<random>'):

print row.name

Carl

Alex

Bob

orderby='<random>'の使用はGAE上ではサポートされません。しかし、このような状況や、同様に、組み込みが十分でないような他の多くの場合は、次のように取り込むことができます:

The use of orderby='<random>' is not supported on GAE. However, in this situation and likewise in many others where builtins are insufficient, imports can be used:

1.

2.

import random

rows=db(...).select().sort(lambda row: random.random())

レコードを複数のフィールドに関してソートすることができます。これはフィールドを"|"によって連結することで可能です:

And you can sort the records according to multiple fields by concatenating them with a "|":

1.

2.

3.

4.

5.

6.

>>> for row in db().select(

db.person.ALL, orderby=db.person.name|db.person.id):

print row.name

Carl

Bob

Alex

orderbyと一緒にgroupbyを用いて、指定したフィールドの同じ値を持つレコードをグループ化することができます(これはバックエンド固有のもので、GAEでは利用できません):

Using groupby together with orderby, you can group records with the same value for the specified field (this is back-end specific, and is not on the GAE):

1.

2.

3.

4.

5.

6.

7.

>>> for row in db().select(

db.person.ALL,

orderby=db.person.name, groupby=db.person.name):

print row.name

Alex

Bob

Carl

distinct=Trueの引数を用いると、重複のないレコードだけを選択したい場合に指定することができます。すべての指定したフィールドを用いてグループ化するのと同じ効果を持ちます。ただしこの場合、ソートは必要ありません。distinctを用いるとき、ALLのフィールドの選択をしないことは重要です。特に、"id"フィールドの選択をしないでください。この場合、すべてのレコードが常に重複なしの状態になってしまいます。

With the argument distinct=True, you can specify that you only want to select distinct records. This has the same effect as grouping using all specified fields except that it does not require sorting. When using distinct it is important not to select ALL fields, and in particular not to select the "id" field, else all records will always be distinct.

以下に例を示します:

Here is an example:

1.

2.

3.

4.

5.

>>> for row in db().select(db.person.name, distinct=True):

print row.name

Alex

Bob

Carl

limitbyを使用すると、レコードの一部を選択することができます(以下の例では、0から始まる最初の2つのが選択されます):

With limitby, you can select a subset of the records (in this case, the first two starting at zero):

1.

2.

3.

4.

>>> for row in db().select(db.person.ALL, limitby=(0, 2)):

print row.name

Alex

Bob

論理演算子

Logical Operators

クエリはANDの二項演算子"&"を用いて組み合わせることができます:

Queries can be combined using the binary AND operator "&":

1.

2.

3.

>>> rows = db((db.person.name=='Alex') & (db.person.id>3)).select()

>>> for row in rows: print row.id, row.name

4 Alex

ORの二項演算子"|"も同様です:

and the binary OR operator "|":

1.

2.

3.

>>> rows = db((db.person.name=='Alex') | (db.person.id>3)).select()

>>> for row in rows: print row.id, row.name

1 Alex

"!="の二項演算子によってクエリ(またはサブクエリ)を否定できます:

You can negate a query (or sub-query) with the "!=" binary operator:

1.

2.

3.

4.

>>> rows = db((db.person.name!='Alex') | (db.person.id>3)).select()

>>> for row in rows: print row.id, row.name

2 Bob

3 Carl

または、"~"単項演算子による明示的な否定によっても可能です:

or by explicit negation with the "~" unary operator:

1.

2.

3.

4.

>>> rows = db((~db.person.name=='Alex') | (db.person.id>3)).select()

>>> for row in rows: print row.id, row.name

2 Bob

3 Carl

Pythonにおける"AND"と"OR"演算子のオーバーロードの制約により、これらはクエリの形成には使用できません。代わりに二項演算子を使用する必要があります。

Due to Python restrictions in overloading "AND" and "OR" operators, these cannot be used in forming queries. The binary operators must be used instead.

count, delete, update

セット内のレコードをカウントすることができます:

You can count records in a set:

1.

2.

>>> print db(db.person.id > 0).count()

3

セット内のレコードを削除することができます:

You can delete records in a set:

1.

>>> db(db.person.id > 3).delete()

セット内のすべてのレコードを更新することができます。これは、更新が必要なフィールドに対応する名前付き引数を渡すことで可能です。

And you can update all records in a set by passing named arguments corresponding to the fields that need to be updated:

1.

>>> db(db.person.id > 3).update(name='Ken')

Expressions

更新文に割り当てられる値は式でも可能です。たとえば、次のようなモデルで考えてください

The value assigned an update statement can be an expression. For example consider this model

1.

2.

3.

4.

5.

>>> db.define_table('person',

Field('name'),

Field('visits', 'integer', default=0))

>>> db(db.person.name == 'Massimo').update(

visits = db.person.visits + 1)

クエリで使用される値もまた、式にすることができます

The values used in queries can also be expressions

1.

2.

3.

4.

5.

>>> db.define_table('person',

Field('name'),

Field('visits', 'integer', default=0),

Field('clicks', 'integer', default=0))

>>> db(db.person.visits == db.person.clicks + 1).delete()

update_record

web2pyではまた、update_recordを用いてすでにメモリにある単一のレコードを更新することが可能です。

web2py also allows updating a single record that is already in memory using update_record

1.

2.

3.

>>> rows = db(db.person.id > 2).select()

>>> row = rows[0]

>>> row.update_record(name='Curt')

これは次のものと混同しないでください

This should not be confused with

1.

>>> row.update(name='Curt')

その理由は、単一のrowに対して、updateメソッドはrowオブジェクトを更新しますが、update_recordのようにデータベースのレコードを更新することはないからです。

because for a single row, the method update updates the row object but not the database record, as in the case of update_record.

first and last

レコードを保持したRowsオブジェクトが与えられたとき、次のようにすることができます:

Given a Rows object containing records:

1.

2.

3.

>>> rows = db(query).select()

>>> first_row = rows.first()

>>> last_row = rows.last()

これは以下のものに相当します。

are equivalent to

1.

2.

>>> first_row = rows[0] if len(rows)>0 else None

>>> last_row = rows[-1] if len(rows)>0 else None

as_dict and as_list

Rowオブジェクトは、as_dict()メソッドを用いて標準の辞書にシリアライズすることが可能です。Rowsオブジェクトは、as_list()メソッドを用いて辞書のリストにシリアライズすることが可能です。例をいくつか示します:

A Row object can be serialized into a regular dictionary using the as_dict() method and a Rows object can be serialized into a list of dictionaries using the as_list() method. Here are some examples:

1.

2.

3.

>>> rows = db(query).select()

>>> rows_list = rows.as_list()

>>> first_row_dict = rows.first().as_dict()

これらのメソッドは、Rowsを汎用的なビューに渡したり、Rowsをセッションに保存したりするのに便利です(Rowsオブジェクト自体は、開いているDB接続への参照があるのでシリアライズできません):

These methods are convenient for passing Rows to generic views and or to store Rows in sessions (since Rows objects themselves cannot be serialized since contain a reference to an open DB connection):

1.

2.

3.

>>> rows = db(query).select()

>>> session.rows = rows # not allowed!

>>> session.rows = rows.as_list() # allowed!

find, exclude, sort

2つの選択を行い、その1つが前回の選択のサブセットを保持しているようなことを実行したいときがよくあります。この場合、データベースに再びアクセスするのは要領を得ません。find、exclude、sortオブジェクトを利用すると、Rowsオブジェクトを操作し、データベースのアクセスなしにもう1つのものを生成することが可能になります。具体的には次のようになります:

There are times when one needs to perform two selects and one contains a subset of a previous select. In this case it is pointless to access the database again. The find, exclude andsort objects allow you to manipulate a Rows objects and generate another one without accessing the database. More specifically:

  • find は、条件でフィルタされた新規のRowsセットを返します。元のものはそのままです。

  • returns a new set of Rows filtered by a condition and leaves the original unchanged.

  • exclude は、条件でフィルタされた新規のRowsセットを返します。それらは元のものから取り除かれます。

  • returns a new set of Rows filtered by a condition and removes them from the original Rows.

  • sort は、条件でソートされた新規のRowsセットを返します。元のものはそのままです。

  • returns a new set of Rows sorted by a condition and leaves the original unchanged.

これらすべてのメソッドは、単一の引数として、各行に対して作用する関数をとります。

All these methods take a single argument, a function that acts on each individual row.

これはその使用例です:

Here is an example of usage:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

>>> db.define_table('person',Field('name'))

>>> db.person.insert(name='John')

>>> db.person.insert(name='Max')

>>> db.person.insert(name='Alex')

>>> rows = db(db.person.id>0).select()

>>> for row in rows.find(lambda row: row.name[0]=='M'):

print row.name

Max

>>> print len(rows)

3

>>> for row in rows.exclude(lambda row: row.name[0]=='M'):

print row.name

Max

>>> print len(rows)

2

>>> for row in rows.sort(lambda row: row.name):

print row.name

Alex

John

これらは組み合わせることができます:

They can be combined:

1.

2.

3.

4.

5.

6.

7.

8.

>>> rows = db(db.person.id>0).select()

>>> rows = rows.find(

lambda row: 'x' in row.name).sort(

lambda row: row.name)

>>> for row in rows:

print row.name

Alex

Max