0

2人の友人の間で相互の友人を見つけるためのmysqlクエリが必要ですが、exの一方通行の関係でユーザーの友情を維持しています。

最初はユーザーテーブルです

id  name
1   abc
2   xyz
3   pqr

2番目のテーブルは友達です

id user_id friend_id
1   1      2
2   1      3
3   2      3

ここで、abc(id=1) は xyz(id=2) の友人であると言えますが、xyz が abc の友人であるのと同様に、abc(id=1) と xyz(id= 2) それは pqr なので、そのための mysql クエリが必要です。

4

2 に答える 2

2

改訂

このクエリは、friend テーブル内の行の "一方向" の関係を "双方向" の関係と見なします。つまり、友人関係:('abc','xyz')は逆関係: と同等であると見なされます('xyz','abc')。(注: 両方の行がテーブルに表示されないという保証はありません。そのため、注意する必要があります。UNION演算子は便利に重複を排除します。)

このクエリは、次の仕様を満たす必要があります。

SELECT mf.id
     , mf.name
  FROM (
         SELECT fr.user_id AS user_id
              , fr.friend_id AS friend_id
           FROM friend fr
           JOIN users fru
             ON fru.id = fr.user_id
          WHERE fru.name IN ('abc','xyz')
          UNION
         SELECT fl.friend_id AS user_id
              , fl.user_id AS friend_id
           FROM friend fl
           JOIN users flf
             ON flf.id = fl.friend_id
          WHERE flf.user IN ('abc','xyz')
       ) f
  JOIN users mf
    ON mf.id = f.friend_id
 GROUP BY mf.id, mf.name
HAVING COUNT(1) = 2
 ORDER BY mf.id, mf.name

SQLフィドルはこちらhttp://sqlfiddle.com/#!2/b23a5/2

これに到達する方法の詳細な説明を以下に示します。以下の元のクエリは、フレンド テーブルの行が「一方向」の関係を表していると想定していました。つまり、「'abc' ff 'xyz'」は「 」を意味するものではありません'xyz' ff 'abc'。しかし、OP からの追加のコメントは、そうではないことを示唆していました。


に一意の制約がある場合friend(user_id,friend_id)、結果を取得する 1 つの方法は、各ユーザーのすべての友達を取得し、その友達の行数を取得することです。friend_idカウントが 2 の場合、特定のユーザーが「abc」と「xyz」の両方に表示されることがわかります。

SELECT mf.id
     , mf.name
  FROM friend f
  JOIN users uu
    ON uu.id = f.user_id
  JOIN users mf
    ON mf.id = f.friend_id
 WHERE uu.name IN ('abc','xyz')
 GROUP BY mf.id, mf.name
HAVING COUNT(1) = 2
 ORDER BY mf.id, mf.name

(このアプローチを拡張して、IN リストにさらに多くのユーザーを含め、COUNT(1) と比較する値を変更することにより、3 人以上のユーザーの共通の友人を見つけることもできます。

指定した結果セットを返すクエリはこれだけではありません。他にも入手方法があります。


同等の結果を得る別の方法:

SELECT u.id
     , u.name
  FROM ( SELECT f1.friend_id
           FROM friend f1
           JOIN users u1
             ON u1.id = f1.user_id
          WHERE u1.name = 'abc'
       ) t1
  JOIN ( SELECT f2.friend_id
           FROM friend f2
           JOIN users u2
             ON u2.id = f2.user_id
          WHERE u2.name = 'xyz'
       ) t2
    ON t2.friend_id = t1.friend_id
  JOIN users u
    ON u.id = t1.friend_id
 ORDER BY u.id, u.name

ノート

これらのクエリは、ユーザー「abc」が「xyz」(WHERE 句で指定された 2 つのユーザー名) のフレンドであるかどうかをチェックしません。「abc」と「xyz」の共通の友人を見つけるだけです。


ファローアップ

上記のクエリは、指定された要件、および質問で提供されているすべての例とテスト ケースを満たしています。

このリレーションシップ テーブルの行を、単なる「一方向」のリレーションシップではなく、「双方向」のリレーションシップと見なしたいように思えます。友人関係 ('abc','xyz') を ('xyz','abc') と同等のものと見なしたいようです。

それを取得するには、クエリで逆行を作成するだけで済みます。これにより、クエリが簡単になります。これらの行 ('abc','xyz') と ('xyz','abc') の両方が既に存在する場合、それらを反転するときにそれらの重複を作成しないように注意する必要があります。

逆行を作成するには、次のようなクエリを使用できます。(users テーブルへの JOIN がなく、id 値のみを使用する場合は、これを見るのが簡単です。

SELECT fr.user_id
     , fr.friend_id 
  FROM friend fr
 WHERE fr.user_id IN (1,2)
 UNION
SELECT fl.friend_id AS user_id
     , fl.user_id AS friend_id
  FROM friend fl
 WHERE fl.friend_id IN (1,2)

user_id および friend_id テーブルに述語を含めない方が簡単ですが、これを実現するには非常に大きな (そして高価な) 行セットになる可能性があります。

于 2013-07-17T03:45:59.240 に答える
0

これを試して:

友達1と2の共通の友達を取得したい場合

select friend_id into #tbl1 from users where user_id = 1

select friend_id into #tbl2 from users where friend_id = 2

select id, name from users where id in(select friend_id from #tbl1 f1, #tbl2 f2 where f1.friend_id=f2.friend_id)
于 2013-07-17T13:24:44.880 に答える