1対多のリレーション

□未翻訳

□翻訳中

■翻訳完了(細田謙二)

■レビュー(Omi Chiba)

1対多のリレーション

web2pyのDALを用いて1対多のリレーションをどのように実装するかを説明するために、"person"テーブルを参照するもう1つの"dog"テーブルを定義します。"person"もここで再定義します:

To illustrate how to implement one to many relations with the web2py DAL, define another table "dog" that refers to the table "person" which we redefine here:

1.

2.

3.

4.

5.

6.

7.

>>> db.define_table('person',

Field('name'),

format='%(name)s')

>>> db.define_table('dog',

Field('name'),

Field('owner', db.person),

format='%(name)s')

"dog"テーブルは、dogの名前(name)とdogの飼い主(owner)という2つのフィールドを持ちます。フィールドの型が他のテーブルのとき、そのフィールドが他のテーブルをそのidによって参照することを意図しています。実際、実在の型の値を出力し、得ることができます:

Table "dog" has two fields, the name of the dog and the owner of the dog. When a field type is another table, it is intended that the field reference the other table by its id. In fact, you can print the actual type value and get:

1.

2.

>>> print db.dog.owner.type

reference person

ここで、2つはAlexによって所有され、1つはBobによって所有された3匹のdogsを挿入します:

Now, insert three dogs, two owned by Alex and one by Bob:

1.

2.

3.

4.

5.

6.

>>> db.dog.insert(name='Skipper', owner=1)

1

>>> db.dog.insert(name='Snoopy', owner=1)

2

>>> db.dog.insert(name='Puppy', owner=2)

3

他のいかなるテーブルに対して行ったように選択することができます:

You can select as you did for any other table:

1.

2.

3.

4.

>>> for row in db(db.dog.owner==1).select():

print row.name

Skipper

Snoopy

dogはpersonへの参照を持っているため、personは複数のdogsを持つことができます。したがって、personテーブルのレコードはこのとき、dogという新規の属性を獲得します。これにより、すべてのpersonsに対してループを回して、それらのdogsを取得することが簡単にできるようになります:

Because a dog has a reference to a person, a person can have many dogs, so a record of table person now acquires a new attribute dog, which is a Set, that defines the dogs of that person. This allows looping over all persons and fetching their dogs easily:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

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

print person.name

for dog in person.dog.select():

print ' ', dog.name

Alex

Skipper

Snoopy

Bob

Puppy

Carl

内部結合(Inner Joins)

Inner Joins

同様の結果を得るための別の方法は、join、具体的には、INNER JOINを用いることです。web2pyは、次の例のようにクエリが2つ以上のテーブルをリンクするときに、joinを自動的に透過的に実行します。

Another way to achieve a similar result is by using a join, specifically an INNER JOIN. web2py performs joins automatically and transparently when the query links two or more tables as in the following example:

1.

2.

3.

4.

5.

6.

>>> rows = db(db.person.id==db.dog.owner).select()

>>> for row in rows:

print row.person.name, 'has', row.dog.name

Alex has Skipper

Alex has Snoopy

Bob has Puppy

web2pyがjoinを行って、rowsが、一緒にリンクされた各テーブル由来の2つのレコードを含んでいることを見てください。2つのレコードは競合する名前のフィールドを持つ可能性があるので、rowからのフィールド値を取り出すときに、テーブルを指定する必要があります。つまり、次のことをする前は:

Observe that web2py did a join, so the rows now contain two records, one from each table, linked together. Because the two records may have fields with conflicting names, you need to specify the table when extracting a field value from a row. This means that while before you could do:

1.

row.name

これがpersonの名前なのか、dogの名前なのかは明らかでした。joinの結果においては、次のようにより明示的なものにする必要があります:

and it was obvious whether this was the name of a person or a dog, in the result of a join you have to be more explicit and say:

1.

row.person.name

または:

or:

1.

row.dog.name

左外部結合(Left Outer Join)

Left Outer Join

Carlは彼が犬を持っていないので、上記のリストには現れなかったことに気づいてください。personsと(所持しているならば)彼らのdogsを(彼らがdogsを所持しているかに関係なく)選択しようとした場合、LEFT OUTER JOINを実行する必要があります。これは、selectコマンドの"left"引数を用いて行うことができます。以下がその例です。

Notice that Carl did not appear in the list above because he has no dogs. If you intend to select on persons (whether they have dogs or not) and their dogs (if they have any), then you need to perform a LEFT OUTER JOIN. This is done using the argument "left" of the select command. Here is an example:

1.

2.

3.

4.

5.

6.

7.

8.

9.

>>> rows=db().select(

db.person.ALL, db.dog.ALL,

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

>>> for row in rows:

print row.person.name, 'has', row.dog.name

Alex has Skipper

Alex has Snoopy

Bob has Puppy

Carl has None

ここで:

where:

1.

left = db.dog.on(...)

これはleft joinクエリを行います。db.dog.onの引数は、joinに必要な条件になります(上述のinner joinで使用したものと同じです)。left joinの場合、どのフィールドを選択するかは明示的にする必要があります。

does the left join query. Here the argument of db.dog.on is the condition required for the join (the same used above for the inner join). In the case of a left join, it is necessary to be explicit about which fields to select.

グループ化とカウント

Grouping and Counting

結合(join)を行うとき、特定の条件に従って行をグループ化し、カウントしたい場合があります。たとえば、各personにおいて所有するdogsの数をカウントするなどです。web2pyではこれも同様に行うことができます。初めに、カウント演算子が必要になります。第2に、personテーブルをdogテーブルを所有者(owner)によってjoinします。第3に、すべての行(person + dog)を選択し、person毎にそれらをグループ化して、グループ化している最中にカウントします:

When doing joins, sometimes you want to group rows according to certain criteria and count them. For example, count the number of dogs owned by every person. web2py allows this as well. First, you need a count operator. Second, you want to join the person table with the dog table by owner. Third, you want to select all rows (person + dog), group them by person, and count them while grouping:

1.

2.

3.

4.

5.

6.

>>> count = db.person.id.count()

>>> for row in db(db.person.id==db.dog.owner).select(

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

print row.person.name, row[count]

Alex 2

Bob 1

(組み込みの)カウント演算子はフィールドとして用いられていることに注意してください。ここでの唯一の問題は、どのように情報を取り出すかにあります。各行は明らかに1人のpersonとカウントを含んでいます。しかし、カウントはpersonのフィールドではなく、テーブルでもありません。では、どこに行くのでしょうか?キーがクエリの式自体と同じであるレコードを表現するような格納オブジェクトに行きます。

Notice the count operator (which is built-in) is used as a field. The only issue here is in how to retrieve the information. Each row clearly contains a person and the count, but the count is not a field of a person nor is it a table. So where does it go? It goes into the storage object representing the record with a key equal to the query expression itself.