これは多対多の関係です。これにはリレーター テーブルが必要です。
create table Person (
person_id int not null primary key,
username varchar(100) not null,
... other_cols ...
)
create table Buddy (
person_id1 int not null,
person_id2 int not null,
primary key (person_id1, person_id2),
foreign key (person_id1) reference Person (person_id),
foreign key (person_id2) reference Person (person_id)
)
したがって、Person テーブルには、明らかに各 Person に対して 1 つの行が含まれます。非正規化されるため、バディに関するあらゆるデータが含まれます。代わりに、Buddy テーブルには人物間の関係が含まれます。
Person テーブルに次のようなものがあるとします。
person_id username
1 George
2 Henry
3 Jody
4 Cara
Henry と Cara は仲良しで、George と Cara も仲良しです。
person_id1 person_id2
2 4
1 4
関係が暗黙的に相互にならないようにする必要がある場合は、それを明示的にするために追加の行を追加する必要があります。ここで、ヘンリーはカーラを仲間と見なし、カーラも同様にヘンリーを仲間と見なし、ジョージはカーラを仲間と見なしますが、カーラはジョージと往復しません。
person_id1 person_id2
2 4
4 2
1 4
欠落している 4 1 は、Cara が George をバディと見なしていないことを示します。これにより、物事が非常にきれいに保たれ、データの異常が回避されます。Person データをいじることなく関係を調整できます。また、Person を削除すると、関連するすべての関係が自動的に削除されるように、外部キーにカスケード削除ルールを定義することもできます。逆に、その代わりに、restrict (デフォルト) を外部キーに指定して、関係がまだ定義されている Person の削除を防ぐことができます。
クエリも簡単です:
Cara には何人の仲間がいますか (仲間リストの関係は暗黙的であると仮定しましょう):
select count(*) from Person
join Buddy on person_id = person_id1 or person_id = person_id2
where name = 'Cara'
関係が暗示されていない場合は、代わりに次のように列の名前を変更することをお勧めします。
person_id considers_as_buddy_id
2 4
4 2
1 4
4 3
select count(*) from Person P
join Buddy B on P.person_id = B.person_id
where name = 'Cara'
これは、Cara が仲間とみなす人の数を返します。この場合 2. Jody は Cara を相棒とは考えていませんが、相互の関係を調べるには、次のようにします。
select count(*) from Person P
join Buddy B on P.person_id = B.person_id and
B.considers_as_buddy_id = P.person_id
where name = 'Cara'