9

質問に目を通しましたが、必要なことを正確に行うものは何も見つかりません。また、自分で行う方法もわかりません。

ユーザー テーブルとフレンド リンク テーブルの 2 つのテーブルがあります。user テーブルは、すべてのユーザーのテーブルです。

    +---------+------------+---------+---------------+
    | user_id | first_name | surname |     email     |
    +---------+------------+---------+---------------+
          1         joe       bloggs    joe@test.com
          2         bill      bloggs    bill@test.com
          3         john      bloggs    john@test.com
          4         karl      bloggs    karl@test.com

私の友人リンク テーブルには、ユーザー間のすべての関係が表示されます。次に例を示します。

    +--------=+---------+-----------+--------+
    | link_id | user_id | friend_id | status |
    +---------+---------+-----------+--------+
       1         1          3           a
       2         3          1           a
       3         4          3           a
       4         3          4           a
       5         2          3           a
       6         3          2           a

ステータス列の a は承認済みを意味することに注意してください。また、r (リクエスト) と d (拒否) がある場合もあります。

私がやりたいのは、ユーザーが検索を行うと、現在まだ友達になっていないユーザーのリストと、各ユーザーが何人の共通の友達を持っているかを返すクエリを作成することです。

現在、友達ではないすべてのユーザーのクエリを取得できました。したがって、検索を実行しているユーザーのユーザー ID が 1 の場合:

SELECT u.user_id,u.first_name,u.surname
FROM users u
    LEFT JOIN friend_links fl
        ON u.user_id = fl.user_id AND 1 IN (fl.friend_id)
WHERE fl.friend_id IS NULL
AND u.user_id != 1
AND surname LIKE 'bloggs'

それでは、返された各ユーザーの共通の友達の数をどのように数えますか?

編集:

私は私の質問で特に明確になっているとは思わないのと同じように編集します。

現在上記のクエリを実行すると、次の一連の結果が生成されます。

    +---------+------------+---------+
    | user_id | first_name | surname |
    +---------+------------+---------+
          2         bill      bloggs
          4         karl      bloggs

これらは、現在 joe bloggs (ユーザー ID 1) と友達ではない姓の bloggs に一致するユーザーです。

次に、これらのユーザーのそれぞれが、検索を行っているユーザーと共通の友人を何人持っているかを知りたいので、返される結果は次のようになります。

    +---------+------------+---------+--------+
    | user_id | first_name | surname | mutual |
    +---------+------------+---------+--------+
          2         bill      bloggs     1
          4         karl      bloggs     1

joe bloggs (ユーザー ID 1) は john bloggs の友達であり、john bloggs は両方の返されたユーザーの友達であるため、これらの返されたユーザーにはそれぞれ 1 人の共通の友達がいます。

これがもう少し明確であることを願っています。

ありがとう。

4

3 に答える 3

6

次のように、friend_id フィールドで friend_links テーブルを自分自身に結合することで、共通の友達を見つけることができます。

SELECT *
FROM friend_links f1 INNER JOIN friend_links f2
  ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person1
  AND f2.user_id = $person2

ただし、最悪の場合、これは基本的にfriend_linksテーブルの行数を2乗することになり、行数が少なくなるとサーバーを簡単にジャッキアップできることに注意してください. より良いオプションは、ユーザーごとに 2 つのサブクエリを使用し、それらの結果を結合することです。

SELECT *
FROM (
  SELECT *
  FROM friend_links
  WHERE user_id = $person1
) p1 INNER JOIN (
  SELECT *
  FROM friend_links
  WHERE user_id = $person1
) p2
  ON p1.friend_id = p2.friend_id

また、いずれにしても一意でなければならないため、代理キーlink_idを削除して主キーのみを作成することで、friend_links テーブルを簡素化できます。(user_id,friend_id)


編集:

これは、まだ友達ではないユーザーを検索する元のクエリにどのように適用されますか? 可能であれば、両方を単一のクエリで実行したいですか?

SELECT f2.user_id, COUNT(*) 'friends_in_common'
FROM friend_links f1 LEFT JOIN friend_links f2
  ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person
GROUP BY f2.user_id
ORDER BY friends_in_common DESC
LIMIT $number

user_idまた、制約をWHERE句からJOIN条件に移動して、自己結合によって作成されたデータ セットのサイズを縮小し、2 番目の例のようにサブクエリを使用できないようにすることも考えています。

于 2012-10-26T17:40:58.670 に答える
3

このクエリは、ユーザー 1 と友達ではなく、姓が一致する人を一覧表示します'%bloggs%'

SELECT
  users.user_id,
  users.first_name,
  users.surname,
  Sum(IF(users.user_id = friend_links_1.friend_id, 1, 0)) As mutual
FROM
  users inner join
    (friend_links INNER JOIN friend_links friend_links_1
     ON friend_links.friend_id = friend_links_1.user_id)
  ON friend_links.user_id=1 AND users.user_id<>1
WHERE
  users.surname LIKE '%bloggs%'
GROUP BY
  users.user_id, users.first_name, users.surname
HAVING
  Sum(IF(users.user_id = friend_links.friend_id, 1, 0))=0

ON 句のユーザー ID と WHERE 句の姓を変更するだけです。私はそれが今正しく動作するはずだと思います!

于 2012-10-29T10:51:06.160 に答える
0

AがBの友達なら、BもAの友達?2 つのリンクの代わりに (そして friends_links の 2 つの行の代わりに) 1 つのリンクを使用する方がよいのではないでしょうか? 次に、status1 と status2 の 2 つのステータス列を使用する必要があり、status1 = status2 = "a" の場合にのみ、A は B のフレンドになります。

共通の友達を表示するには、多くの方法があります。たとえば、次のようになります。

SELECT friend_id
FROM friend_links
WHERE friend_links.user_id = $user1 or friend_links.user_id = $user2
  AND NOT (friend_links.friend_id = $user1 or friend_links.friend_id = $user2)
GROUP BY friend_id
HAVING Count(*)>1

そして、このクエリは、各ユーザーと彼/彼女の友人ではないすべての人に対して表示されます:

SELECT
  users.user_id,
  users.first_name,
  users_1.user_id,
  users_1.first_name
FROM
  users INNER JOIN users users_1 ON users.user_id <> users_1.user_id
WHERE
  NOT EXISTS (SELECT *
              FROM friend_links
              WHERE
                friend_links.user_id = users.user_id
                AND friend_links.friend_id = users_1.user_id)

(私がチェックしなかったのは友情のステータスだけだと思いますが、そのチェックを追加するのは簡単です).

私はまだ取り組んでいますが、これら 2 つのクエリをうまく組み合わせるのは簡単ではありません。したがって、これは正確な答えではありません。私が試したいくつかのアイデアを示しているだけです。

しかし、正確に何が必要ですか?友達ではないすべてのユーザーと共通の友達の数を返すクエリ、または user_id が既に指定されているクエリ?

いくつかのコードでは、あなたの質問に答えることは問題ではありません...しかし、SQL を使用するだけで良い方法が必要です! :)

編集:

これに対するより良い解決策があるかどうかはまだ疑問に思っています。特に次のクエリは非常に遅くなる可能性がありますが、これはうまくいくようです:

SELECT
  users_1.user_id,
  users_2.user_id,
  Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links_1.friend_id, 1, 0)) As CommonFriend
FROM
  users users_1 INNER JOIN users users_2
    ON users_1.user_id <> users_2.user_id,
  (friend_links INNER JOIN friend_links friend_links_1
    ON friend_links.friend_id = friend_links_1.user_id)
GROUP BY
  users_1.user_id,
  users_2.user_id
HAVING
  Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links.friend_id, 1, 0))=0

(前回同様、友好度は確認していません)

ユーザーが指定されている場合は、置くこともできますがWHERE users_1.user_id=$user1、ユーザー テーブルを 1 つだけ残して、そのユーザーで次の INNER JOIN をフィルター処理することをお勧めします。

于 2012-10-27T14:26:11.623 に答える