MySQL - 不会产生不需要的结果

时间:2013-01-22 17:12:19

标签: php mysql join not-exists notin

我有以下表格:

user
+-----------------------------------------------+
|  user_id    |  username   | Password | ...    |
+-----------------------------------------------+
|     1       |     a       |  ***     | ...    |
+-----------------------------------------------+
|     2       |     b       |  ***     | ...    |
+-----------------------------------------------+
|     3       |     c       |  ***     | ...    |
+-----------------------------------------------+
|     4       |     d       |  ***     | ...    |
+-----------------------------------------------+
|     5       |     e       |  ***     | ...    |
+-----------------------------------------------+

friends
+-----------------------------------------------+
|  f_id    |  user_id   | friend_id | ...       |
+-----------------------------------------------+
|     1    |     4      |  2        | ...       |
+-----------------------------------------------+
|     2    |     4      |  1        | ...       |
+-----------------------------------------------+
|     3    |     4      |  5        | ...       |
+-----------------------------------------------+
|     4    |     4      |  3        | ...       |
+-----------------------------------------------+

我希望将所有可用的用户添加为好友(在这种情况下,user_id 1将有3个好友添加(2, 3, 5)。但是,使用以下SQL statement below我只能添加1个用户(4)

$sql = "SELECT * FROM user WHERE user.user_id NOT IN 
(SELECT friends.friend_id FROM friends) AND 
user.user_id <> $_SESSION['id']." ORDER BY RAND() LIMIT 5";

但是当我以用户4登录时没有可用的用户可用,这种方法很有效。这对我来说有点棘手。任何想法都会非常感激。

由于

6 个答案:

答案 0 :(得分:2)

这个怎么样? null显示用户4不应将用户4添加为朋友的位置。实际上,您可以按And FID is not null过滤掉它。如果您希望根据select to be added friends session id特定用户,那么您也可以在另一个条件下对其进行指定:)

更新了添加其他联接,以确保为朋友显示名称,而不是为其他用户显示。除此之外不再存在4

查询:

select x.id, a.name, x.fid
from users a
join (
select u.id, u.name, f.fid
from users u
left join friends f
on u.id <> f.fid
and u.id <> f.uid) x
on x.fid = a.id
;

结果:

| ID | NAME | FID |
-------------------
|  1 |    b |   2 |
|  1 |    e |   5 |
|  1 |    c |   3 |
|  2 |    a |   1 |
|  2 |    e |   5 |
|  2 |    c |   3 |
|  3 |    b |   2 |
|  3 |    a |   1 |
|  3 |    e |   5 |
|  5 |    b |   2 |
|  5 |    a |   1 |
|  5 |    c |   3 |

对于特定用户,例如1

SQLFIDDLE DEMO USER 1

select x.id, x.fid, a.name
from users a
join 
(select u.id, f.fid
from users u
inner join friends f
on u.id <> f.fid
and u.id <> f.uid
and u.id = 1)x
on x.fid = a.id
;

| ID | FID | NAME |
-------------------
|  1 |   2 |    b |
|  1 |   3 |    c |
|  1 |   5 |    e |

答案 1 :(得分:1)

您的SQL查询正在做的是:获取id不等于任何friend_id的所有用户,而不是当前用户(我假设)。

你想要的是检查朋友表中的friend_id和user_id对没有记录,如下所示:$ sql =

"SELECT * FROM user WHERE user.user_id NOT IN 
(SELECT friends.friend_id FROM friends WHERE friend.user_id = user.user_id) AND 
user.user_id <> $_SESSION['id']." ORDER BY RAND() LIMIT 5";

答案 2 :(得分:1)

您可以尝试NOT IN JOIN表,而不是将friends与子查询一起使用。

JOIN两次编辑。一旦1user_id1friend_id11。然后,我收到的所有用户都不是SELECT user.user_id,user.username FROM user LEFT JOIN friends AS fA ON fA.user_id = 1 LEFT JOIN friends AS fB ON fB.friend_id = 1 WHERE user.user_id != 1 AND NOT (user.user_id <=> fB.user_id) AND NOT (user.user_id <=> fA.friend_id) 或{{1}}的朋友。

{{1}}

DEMO:http://sqlfiddle.com/#!2/1a7ae/30

答案 3 :(得分:1)

编辑:

这个怎么样: (in else子句使用无效的id或与登录用户相同的id)

select * from users where id not in
(
   select (
            case
              when uid = 1 then id
              when fid = 1 then uid
             else 0
            end
          ) from friends where uid = 1 or fid = 1
) and id != 1 order by rand() limit 5;

http://sqlfiddle.com/#!2/12de1/62


解决此问题的另一种方法(但可能不是最佳解决方案):

如果用户拥有的朋友数量少于系统中的用户总数,则

下面的联合查询可能不是一个代价高昂的查询,而不是两个表之间的完全联接。

另请不要忘记在uid表的fidfriends列添加索引。

select * from users where id not in 
(
     select id from friends where uid = 1
     union
     select uid from friends where fid = 1
) and id != 1 order by rand() limit 5;

http://sqlfiddle.com/#!2/12de1/40

答案 4 :(得分:0)

您在子查询中缺少where子句,以将其限制为您要排除的当前用户朋友。

$sql = "select * from user u 
    where u.user_id not in 
    (select f.friend_id from friends f where f.user_id = ".$_SESSION['id'].")
    and u.user_id <> ".$_SESSION['id']." ORDER BY RAND() LIMIT 5";

我还建议不要使用字符串连接来执行此操作。 PDO会更安全,你不会有SQL注入的风险。

http://php.net/manual/en/ref.pdo-mysql.php

答案 5 :(得分:0)

SELECT u1.id u1_id
     , u2.id u2_id
  FROM users u1
  JOIN users u2
    ON u2.id <> u1.id
  LEFT
  JOIN friends f
    ON (f.fid = u1.id AND f.uid = u2.id)
    OR (f.fid = u2.id AND f.uid = u1.id)
 WHERE f.id IS NULL;