我创建了一个“建议朋友”的PHP脚本,类似于facebook。我的数据库有2个表,用户(user_id,姓名,个人资料)和朋友(friends_id,user_one,user_two)。我的代码如下:
<?php
//----- gets all friends of my friends -------
$friends_of_friends = mysql_query(" SELECT u.*
FROM (SELECT DISTINCT user_one as user_id
FROM friends
WHERE user_two IN (SELECT user_one as user_id
FROM friends
WHERE user_two = '$session_user_id'
UNION DISTINCT
SELECT user_two
FROM friends
WHERE user_one = '$session_user_id'
)
UNION DISTINCT
SELECT DISTINCT user_two
FROM friends
WHERE user_one IN (SELECT user_one as user_id
FROM friends
WHERE user_two = '$session_user_id'
UNION DISTINCT
SELECT user_two
FROM friends
WHERE user_one = '$session_user_id'
)
) f
JOIN users u
ON u.user_id = f.user_id ");
while ($run_friends= mysql_fetch_assoc($friends_of_friends)) {
$friend_friend_id = $run_friends['user_id'];
// ---- gets friends of my friends that are not my friends -------------------------------
$check_friend_query = mysql_query(" SELECT friends_id from friends WHERE (user_one='$session_user_id' AND user_two='$friend_friend_id') OR (user_one='$friend_friend_id' AND user_two='$session_user_id') ");
if (mysql_num_rows($check_friend_query) != 1){
$not_friends = mysql_query("SELECT `user_id`, `name`, `surname`, `email`, `profile` FROM `users` WHERE (`user_id`='$friend_friend_id' AND `user_id`!='$session_user_id') ");
while ($run_not_friends= mysql_fetch_assoc($not_friends)) {
$not_friend_id = $run_not_friends['user_id'];
echo $not_friend_id;
} //end while
} //end if
} //end while
?>
我的代码工作得很好,并且把我想要的朋友的所有朋友都给了我。是否可以将所有上述代码组合在一个spl语句中?知道怎么做吗?
答案 0 :(得分:1)
您的查询对于您要实现的目标来说似乎非常复杂。据我所知,与原始查询相关的唯一字段是user_one
中的user_two
和friends
以及user_id
中的users
。通过使用子查询,查询的运行时将以exponanti的方式增加。
这意味着你可以将它重写为以下查询,这应该快得多,因为mysql可以缩短很多结果而不必每个子查询。它返回来自某个用户的朋友的朋友,我将从此处称为“x”。不是朋友的朋友的'x'的朋友不会被退回,并且由于最后的AND,它也不会返回用户。
SELECT DISTINCT c.* FROM friends as a, friends as b, users as c
WHERE (a.user_one = 1 AND (
(a.user_two = b.user_one AND b.user_two = c.user_id) OR
(a.user_two = b.user_two AND b.user_one = c.user_id)
) OR (a.user_two = 1 AND (
(a.user_one = b.user_one AND b.user_two = c.user_id) OR
(a.user_one = b.user_two AND b.user_one = c.user_id)
)
)) AND c.user_id != 1
ORDER BY c.`user_id` ASC
要从结果中删除所有来自“x”的直接朋友的用户,您可以使用NOT IN( ... )
。我使用了一个子查询,因为我不相信没有子查询就有办法做到这一点。我本可以加入一个额外的friends
表,但即使我测试当前用户是否是来自c.user_id
的朋友对着新加入的表,查询也可以通过匹配其中任何其他朋友来进行查询的一部分,这是我们不想要的。子查询将(或应该)每个唯一的朋友从朋友执行一次。我认为如果您将这些查询分开并将两个返回的数组相互比较,性能会更好,但这不允许您在查询中使用LIMIT
。
SELECT DISTINCT c.* FROM friends as a, friends as b, users as c
WHERE (a.user_one = 1 AND (
(a.user_two = b.user_one AND b.user_two = c.user_id) OR
(a.user_two = b.user_two AND b.user_one = c.user_id)
) OR (a.user_two = 1 AND (
(a.user_one = b.user_one AND b.user_two = c.user_id) OR
(a.user_one = b.user_two AND b.user_one = c.user_id)
)
)) AND c.user_id != 1 AND
c.user_id NOT IN (
SELECT friends.user_two FROM friends WHERE friends.user_one = 1 UNION
SELECT friends.user_one FROM friends WHERE friends.user_two = 1
)
ORDER BY c.`user_id` ASC
我相信这应该链接到正确的sqlfiddle:http://sqlfiddle.com/#!2/6c14e/2