2014-11-01 24 views
-1

我有三个表:怪异的结果从一个MySQL查询

  1. 用户(所有用户)
  2. 朋友(关系表由ID1和ID2列基本上讲述的是谁的朋友与谁)
  3. 帖子(所有帖子都有写过它们的用户的ID)。

我要选择用户从职位表中写道由朋友表中指定他的朋友写的所有帖子和文章中,我写了这个查询:

SELECT 
posts.ID as ID, 
CONCAT(users.FirstName, ' ', users.LastName) as Name, 
posts.Date as Date, 
posts.Text as Text 
FROM users, posts, friends 
WHERE users.ID = posts.UserID AND 
((posts.UserID = friends.ID1 AND friends.ID2 = '10000007') OR 
(posts.UserID = friends.ID2 AND friends.ID1 = '10000007') 
OR (posts.UserID = '10000007')) 

这给了我他的朋友写了很多额外的行的帖子,我不知道它来自哪里。那么有谁能告诉我查询中的问题在哪里?

回答

0

我可以使用嵌套的SELECT语句解决我的问题:

SELECT 
posts.ID as ID, 
users.ID as UserID, 
CONCAT(users.FirstName, ' ', users.LastName) as Name, 
posts.Date as Date, 
posts.Text as Text 
FROM users, posts 
WHERE users.ID = posts.UserID AND 
(posts.UserID = '10000007' OR 
posts.UserID IN (
SELECT users.ID 
FROM users, friends 
WHERE (friends.ID1 = '10000007' AND users.ID = friends.ID2) 
OR (friends.ID2 = '10000007' AND users.ID = friends.ID1) 
)) 
+1

不要使用嵌套的'SELECT'语句。改用'JOIN'。 – Heavy 2014-11-15 17:03:25

+0

@重要的是为什么呢?我的意思是在SELECT上使用JOIN的优点是什么? – user2073081 2014-11-17 13:47:28

1

我个人认为使用该类型选择语法(SELECT ... FROM表1,表2,表3)是有点混乱读如果你因为它而看到一些奇怪的行为,我不会怀疑它。如何改为:

SELECT DISTINCT 
posts.ID as ID, 
CONCAT (users.FirstName, ' ', users.LastName) as Name, 
posts.Date as Date, 
posts.Text as Text 
FROM 
users 
LEFT JOIN posts ON users.ID = posts.UserID 
LEFT JOIN friends ON (
    (posts.UserID = friends.ID1 AND friends.ID2 = '10000007') OR 
    (posts.UserID = friends.ID2 AND friends.ID1 = '10000007')) 
HAVING 
posts.UserID IS NOT NULL OR friends.ID1 IS NOT NULL 
1

我会这样写。

SELECT posts.ID as ID, 
     CONCAT(users.FirstName, ' ', users.LastName) as Name, 
     posts.Date as Date, 
     posts.Text as Text 

FROM users 

     LEFT JOIN posts 
     ON users.ID = posts.UserID 
     OR posts.UserID IN 
     (SELECT ID2 FROM friends WHERE ID1 = '10000007' 
     UNION 
     SELECT ID1 FROM friends WHERE ID2 = '10000007') 

WHERE users.ID = '10000007' 
1

如果使用IN,就没有必要嵌套的朋友加盟表和用户表:

SELECT 
    posts.ID as ID, 
    users.ID as UserID, 
    CONCAT(users.FirstName, ' ', users.LastName) as Name, 
    posts.Date as Date, 
    posts.Text as Text 
FROM users, posts -- Try to change the old style join to 
        -- FROM users JOIN posts 
        -- ON users.ID = posts.UserID Where ... 
WHERE users.ID = posts.UserID 
AND (posts.UserID = '10000007' OR 
    posts.UserID IN 
     (
     SELECT ID 
     FROM friends 
     WHERE friends.ID1 = '10000007' 
     UNION 
     SELECT ID 
     FROM friends 
     WHERE friends.ID2 = '10000007' 
     ) 
    ) 

你原来的查询,因为您可以根据一对多的关系加入到朋友表将返回重复的行。你有两个选择来改变它。一种方法是添加不同的选择语句。用另一种方式存在,这样的(如果有太多的恶魔为用户,EXISTS会比IN更有效):

SELECT 
    posts.ID as ID, 
    CONCAT(users.FirstName, ' ', users.LastName) as Name, 
    posts.Date as Date, 
    posts.Text as Text 
FROM users 
JOIN posts 
ON users.ID = posts.UserID 
WHERE 
    EXISTS 
     (SELECT 1 
     FROM friends 
      (posts.UserID = friends.ID1 AND friends.ID2 = '10000007') 
      OR 
      (posts.UserID = friends.ID2 AND friends.ID1 = '10000007') 
     ) 
    OR posts.UserID = '10000007'