简体   繁体   English

来自MySql查询的奇怪结果

[英]Weird Result From a MySql Query

I have three tables: 我有三个表:

  1. users (all the users) 用户(所有用户)
  2. friends (relation table consists of ID1 and ID2 columns which basically tells who's friend with who) 朋友(关系表由ID1和ID2列组成,它们基本上告诉谁和谁是朋友)
  3. posts (all the posts with the ID of the user who has written them). 帖子(所有帖子均带有编写该帖子的用户的ID)。

I want to select all the posts that the user wrote from the posts table and the posts written by his friends specified by the friends table, I wrote this query: 我想从用户表中选择用户写的所有信息,以及由朋友表指定的他的朋友所写的信息,我编写了这个查询:

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'))

this gives me the posts written by his friends with many extra rows that I don't know where it came from. 这给了我他的朋友写的帖子,还有很多行,我不知道它来自哪里。 So can anybody tell me where is the problem here in the query? 那么有人可以告诉我查询中的问题在哪里吗?

Personally I think using that type of select syntax (SELECT ... FROM table1, table2, table3) is a little confusing to read and I wouldn't doubt it if you see some weird behavior because of it. 我个人认为使用这种类型的选择语法(SELECT ... FROM table1,table2,table3)有点令人困惑,并且如果您看到一些奇怪的行为,我也不会怀疑。 How about this instead: 怎么样呢:

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

I would write it this way. 我会这样写。

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'

If you use IN , there's no need of nesting join friends table and users table: 如果使用IN ,则不需要嵌套join friends表和users表:

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' 
        )
    )

Your original query will return duplicate rows because you join to friends table based on one to many relationship. 您的原始查询将返回重复的行,因为您基于一对多关系加入了Friends表。 You have two choice to change it. 您有两种选择来更改它。 One way is add distinct to your select statement. 一种方法是在您的选择语句中添加不同的内容。 The other way is using exists like this(If there are too many fiends for a user, EXISTS will be more efficient than IN ): 另一种方法是使用像这样的存在(如果对用户有太多的恶魔,则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'

I was able to solve my problem using nested SELECT statement: 我能够使用嵌套的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)
))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM