两个加入声明

时间:2011-03-23 21:29:39

标签: mysql

所以我有这个问题:

SELECT DISTINCT(b.friend_id) AS possible_id
FROM friend_friends a
    JOIN friends_friends b 
      ON b.user_id = a.friend_id
WHERE a.user_id = 1703122278

它会检索特定用户的朋友的朋友

我有另一个数据库,其中包含那些说他们不是朋友的人的数据。

以下是获取所述非朋友列表的查询:

SELECT friend_id
FROM friends_not_friends
WHERE user_id = 1703122278
AND not_friends = 1

然后我从可能的朋友列表中比较不是朋友的列表,并从列表中删除不是朋友。

如何在不使用子查询的情况下组合这两个查询,而是使用连接?

4 个答案:

答案 0 :(得分:3)

SELECT DISTINCT(b.friend_id) AS possible_id
FROM friend_friends a
  JOIN friends_friends b 
    ON b.user_id = a.friend_id
  LEFT JOIN friends_not_friends n
    ON b.friend_id = n.friend_id
      AND n.user_id = a.user_id
      AND n.not_friends = 1
WHERE a.user_id = 1703122278
  AND n.friend_id IS NULL

这显示了

(1st list of friends of friends of 1703122278)
MINUS
(2nd list of not friends of 1703122278)

我希望你不要

list of friends of
   (friends of 1703122278
    minus
    (2nd list of not friends of 1703122278)
   )

简单地说,这是使用NOT IN的查询。 我个人觉得这些更清楚,但速度可能不太有效。

-- Friends of friends of a user
SELECT DISTINCT(b.friend_id) AS possible_id 
FROM friend_friends b                      -- the b and a aliases
WHERE b.user_id IN                         -- can be removed 
  ( SELECT a.friend_id
    FROM friends_friends a
    WHERE a.user_id = 1703122278
  )
;

和被问到的人:

-- Friends of friends of a user that  
-- are also not not_friends of the user:
SELECT DISTINCT(b.friend_id) AS possible_id  
FROM friend_friends b                      -- the b, a and n aliases
WHERE b.user_id IN                         -- can be removed too
  ( SELECT a.friend_id
    FROM friends_friends a
    WHERE a.user_id = 1703122278
  )
  AND b.friend_id NOT IN 
  ( SELECT n.friend_id
    FROM friends_not_friends n
    WHERE n.user_id = 1703122278
      AND n.not_friends = 1
  )
;

答案 1 :(得分:1)

在oracle中我会使用MINUS运算符。

我认为mysql中有一个相关函数 - 可能是左连接或NOT IN子句

答案 2 :(得分:1)

这是一个过滤两个级别上的“不是朋友”的解决方案(它过滤了用户的非朋友非朋友的朋友用户):

  SELECT
     DISTINCT(b.friend_id) AS possible_id
  FROM
     friend_friends a
     JOIN friend_friends b ON b.user_id = a.friend_id
     LEFT JOIN friends_not_friends nfa
         ON a.friend_id = nfa.user_id and nfa.not_friends = 1
     LEFT JOIN friends_not_friends nfb
         ON b.friend_id = nfb.user_id and nfb.not_friends = 1
  WHERE
     a.user_id = 1703122278
     AND nfa.friend_id IS NULL
     AND nfb.friend_id IS NULL

“技巧”是执行LEFT JOIN并检查是否没有数据(NULL)。

顺便说一句 - 是否有理由不想进行次选?有时LEFT JOIN - 方式更快,但子选择通常是一个不错的选择。

答案 3 :(得分:0)

尝试左外连接到friend_not_friends表(在friend_id上匹配,过滤user_id和not_friends标志),然后消除not_friends中匹配行的行(即消除not_friend id为NOT NULL的行

SELECT DISTINCT(f.friend_id) AS possible_id
  FROM friend_friends a
  JOIN friends_friends f
    ON f.user_id = a.friend_id
  LEFT
  JOIN friends_not_friends n
    ON n.user_id = a.user_id
   AND n.friend_id = f.friend_id
   AND n.not_friends = 1
 WHERE a.user_id = 1703122278
   AND n.user_id IS NULL

诀窍是过滤掉匹配的行,在friends_not_friends表中留下未找到匹配的行。它是查询中的最后一个谓词(n.user_id IS NULL),为您进行过滤。


如果没有使用子查询的要求,那么这样的东西也会起作用:

 SELECT DISTINCT(f.friend_id) AS possible_id
   FROM friend_friends a
   JOIN friends_friends f 
     ON f.user_id = a.friend_id
  WHERE a.user_id = 1703122278
    AND NOT EXISTS 
        ( SELECT 1 
            FROM friends_not_friends n 
           WHERE n.friend_id = f.friend_id
             AND n.user_id = a.user_id
             AND n.not_friends = 1
        )