2012-01-18 9 views
2

ユーザーが友情を互いに関連付けることができるテーブルを作成したいと思います。同時に、このテーブルは、私が取り組もうとしている他のさまざまなテーブル間の1対多の関係になることに関連して動作します。mysql DBにフレンドシップアソシエーションを保存する適切な方法は何ですか

今、私はこの

MEMBER_ID、friend_idような何かを考えています、アクティブ、日付

MEMBER_IDが呼び出しを行ったユーザの列となり、friend_idは、彼らがしている友人の列になります0に保留中、1 =アクティブ、日付は、その特定の行の最後の活動のログに記録された日付になります。

今私の混乱は、私は通常member_idをクエリし、関連するfriend_idのクエリの残りの部分を適切な人物に応じて表示することです。だから、この種の論理を念頭に置いておくと、1回のリクエストにつき2行が必要になると思います。 1つは、その要求のmember_idと要求のfriend_idがテーブルに挿入され、次に1つは反対ですので、毎回それに応じてクエリを実行できます。だから本質的には、この特定のテーブルに要求されたすべてのアクションのためのダブルディッピングのように、私は2つのアクションのように動作させる必要があります。 最適化が進んでいる限り、私には分かりません。だから私の質問では、このような関係のためのデータを扱う適切な方法は何ですか?あるいは、私は実際には、これを扱うアプローチであることを誠実に考えていますか?

+0

最初のモデルは完璧です。第二の部分については、両方の方向を見出すために、ここではすでに多くの答えがあります。短いバージョン:あなたのSELECTクエリを少しfancyfull構築し、両方の方向を簡単に取得します。 –

答えて

6

友だちがの場合、常にの場合、より簡単なクエリのためにデータの冗長性(つまり、行を持つ両方向)を選択するか、やや複雑なクエリを使用して学習することができます。私は個人的には魅力的な理由がなければデータの冗長性を避けたいと思います。スペースとパフォーマンスを浪費するだけではありませんが、強制するときは注意が必要です。単純なCHECKは他の行を参照できず、 DBMSのトリガは、変更テーブルを使用して行うことができる制限があります。

簡単な方法は、友情ごとに1つの行に確実に(それを強制する制約CHECK (member_id < friend_id)を行う)常にfriend_idmember_idに低い値と高い値を挿入することです。あなたが照会する場合次に、あなたは両方の方向に検索を持っています - 例えば、(person_idによって識別される)与えられた人のすべての友達を見つけることは、このようなものになります。この方式ではところで

SELECT * 
FROM 
    person 
WHERE 
    id <> :person_id 
    AND (
     id IN (
      SELECT friend_id 
      FROM friendship 
      WHERE member_id = :person_id 
     ) 
     OR 
     id IN (
      SELECT member_id 
      FROM friendship 
      WHERE friend_id = :person_id 
     ) 
    ) 

を、あなたはmember_idfriend_idという名前を、たとえばfriend1_idfriend2_idと変更するといいでしょう。

+0

ちょうど注:上記のコードでINキーワードを使用することは、MySQLで最適化されていないため、良い考えではありません。大きなテーブルでは、結果が遅くなることがあります。 – maliayas

+0

@maliayasはい、MySQLはサブクエリを最適化しません。この特定のケースにおける実際の問題であるかどうかは、現実的な量のデータを測定することによってのみ判断できます。ここではパフォーマンス上の問題はないはずですが、私が間違っていると、基本的に同じクエリを表現する方法があり、MySQLの欠点を回避できます(例:JOIN)。 –

1

美しい - あなたのテーブルには問題ありません。 ALSO

:このカーディナリティは、または「多くの多くの」「多くの1つ」である場合 が、私はよく分からない:

http://en.wikipedia.org/wiki/Cardinality_%28data_modeling%29

Q:私は、私は通常、照会しまう照会しましたMEMBER_ID、次いで に応じて適切な人々

Aにデータを表示するには、関連するfriend_idののオフクエリの 残りをベース:率直に言って、私は表示されません「友人」への「友人」への質問、または「友人との友人」への質問(または、友人を共有する友人)。再び、それはよさそうだ。

0

のようにヘルパー表を紹介:私は、これは単なる一例として、クエリを入れて、あなたが持っているものとかなり似ていると思う

users 
user_id, name, ... 

friendship 
user_id, friend_id, .... 

select u.name as user, u2.name as friend from users u 
    inner join friendship f on f.user_id = u.user_id 
    inner join users u2 on u2.user_id = f.friend_id 

。それを見て

+0

関係の両側が追加された場合は、潜在的な重複エントリ。 – Kenaniah

+0

実際に列の名前が表示されている場合はありません。双方向が追加された場合、2つの行が意味を成すなら、一方向の関係です。 –

+0

2行出力は結合構造を複雑にします。そうしなければ、結合されたデータに重複が生じるため、別のセットを返すために 'GROUP BY 'を追加する必要があります。 – Kenaniah

5

二つの方法:

WHERE ((friend_id = x AND member_id = y) OR (friend_id = y AND member_id = x)) 

あなたは、単に関係の一の側面を示すことによって照会することが可能になります。両方の面が追加された場合、このメソッドは重複する行が返されることなく動作します。あなたのクエリが

WHERE friend_id = x AND member_id = y 

から構成されるように、関係の両側を加える逆

は、だけでなく、クエリの書き込みが容易でなく、(より良いDBのパフォーマンスを意味する)を計画しやすくなります。

私の投票は後者のオプションです。

関連する問題