0

このトピックに関する結果がたくさんあることは知っていますが、役に立ちませんでした。

user1 と user2 の友人テーブルがあります。

本当の友達とは、user1 が user2 と友達で、user2 が user1 と友達の場合です。

友達リクエストは、user1 が user2 と友達になった場合です。次のようになります。

 user1 | user2
 -------------
 1     | 2
 2     | 1
 1     | 3
 3     | 1
 1     | 5

#1 の本当の友達を取得するためのクエリはどのようになりますか?

私はこれを試しましたが、nullを返しました:

SELECT user2 FROM friends WHERE user1 = 1 AND user2 = 1

また、クエリは友達リクエストをどのように探しますか?

4

3 に答える 3

0
SELECT user2 FROM friends 
  WHERE user1 = 1 
  AND user2 IN (SELECT user1 from friends where user2 = 1);
于 2013-08-20T18:49:11.573 に答える
0

これを取得する 1 つの方法は、JOIN 操作を使用することです。

SELECT f.user2
  FROM friends f
  JOIN friends r
    ON r.user1 = f.user2
   AND r.user2 = f.user1
 WHERE f.user1 = 1

「真の友人」関係が 2 つのタプルの存在によって識別される場合、つまり、 と の間の真の友人関係は1、表のとnの 2 つの行で表されます。(1,n)(n,1)

結合条件の述語は、一致する「逆」タプルを持つ行に返される行を制限します。

注: JOIN 操作は通常、同等の操作IN (subquery)EXISTS (subquery)パターンよりも優れたパフォーマンスを発揮しますが、小さなセットではパフォーマンスの違いは無視できます。パフォーマンスの違いが顕著になるのは、より大きなセットです。

EXISTS 述語を使用すると、同等の結果を返すことができます (通常はあまり効率的ではありません)。

SELECT f.user2
  FROM friends f
 WHERE f.user1 = 1
   AND EXISTS ( SELECT 1
                  FROM friends r
                 WHERE r.user1 = f.user2
                   AND r.user2 = f.user1
              )

または IN 述語:

SELECT f.user2
  FROM friends f
 WHERE f.user1 = 1
   AND f.user2 IN ( SELECT r.user1
                      FROM friends r
                     WHERE r.user2 = f.user1
                  )

(friends(user1,user2) に一意の制約がない場合、JOIN は他のクエリでは返されない重複行を返す可能性がありますが、重複が返されないことを保証するクエリはありません。一意の制約がない場合は、重複を返したくない場合は、これらのステートメントの先頭にある SELECT の後に DISTINCT キーワードを追加するか、これらのステートメントの末尾に GROUP BY f.user2 を追加します。

結果セットをより確定的にする (つまり、クエリを実行するたびに同じ結果を返す) には、ORDER BY 句を追加できます。(ただし、MySQL は暗黙的に GROUP BY 式で ORDER BY を実行するため、GROUP BY では必要ありません。)


ファローアップ

この結果をユーザーテーブルの名前にバインドする方法を説明してください。ありがとうございました。そして、どうすれば「本物ではない」友達を得ることができますか?

ユーザー テーブルから名前を取得するには、id が主キー列であり、user1 列と user2 列がユーザー テーブルへの外部キーであると仮定して、ユーザー テーブルに JOIN を追加するだけです...

SELECT f.user2
     , u.name
  FROM friends f
  JOIN user u
    ON u.id = f.user2
  JOIN friends r
    ON r.user1 = f.user2
   AND r.user2 = f.user1
 WHERE f.user1 = 1

「本物ではない」友人は(1,n)、対応する逆タプルを持たないタプル (表の行) として表されます(n,1)。これらの行を見つけるために、OUTER 結合 (一方の側からすべての行と一致する行を返す) であるアンチ結合パターンを使用し、次に、一致が見つかった行を除外する述語を使用します (一致する場合に null ではないことが保証されている列は、これを行う方法です):

(1,n)これは、一致する がないすべてのタプルを見つけます(n,1):

SELECT f.user2
     , u.name
  FROM friends f
  JOIN user u 
    ON u.id = f.user2
  LEFT
  JOIN friends r
    ON r.user1 = f.user2
   AND r.user2 = f.user1
 WHERE r.user1 IS NULL
   AND f.user1 = 1

一致する行(n,1)がない反対側の行を取得するには、それを反転する必要があります。(1,n)

SELECT f.user1
  FROM friends f
  JOIN user u 
    ON u.id = f.user1
  LEFT
  JOIN friends r
    ON r.user2 = f.user1
   AND r.user1 = f.user2
 WHERE r.user2 IS NULL
   AND f.user2 = 1
于 2013-08-20T18:52:37.423 に答える