2014-05-20 30 views
3

我试图简化我的查询,以便它只包含会话ID(SID)一次。MySQL删除子查询中的重复子句

用户表的抽象结构是:

+----+------+----------+ 
| ID | Name | Username | 
+----+------+----------+ 

友表具有一个抽象的结构,如:

+----+-----------------+----------+--------+---------+ 
| ID |  UserID  | FriendID | Hidden | Deleted | 
| | (Foreign key |   |  |   | 
| | of ID in Users) |   |  |   | 
+----+-----------------+----------+--------+---------+ 

会话表的抽象结构:

+----+-----------------+-----+ 
| ID |  UserID  | SID | 
| | (Foreign key |  | 
| | of ID in Users) |  | 
+----+-----------------+-----+ 

我有以下查询,它已根据前一个查询的答案进行了修改我的。正如你所看到的,会话ID(SID)重复了4次,是否有可能将查询作为一个整体进行压缩,以便SID只需要一次?

SELECT * 
    ,CASE 
     WHEN D.ID IS NULL 
      THEN "Wants to be your friend" 
     ELSE "Friends" 
     END AS STATUS 
FROM (
    SELECT DISTINCT A.ID 
     ,A.NAME 
     ,E.Hidden 
    FROM Users A 
    INNER JOIN Friends E ON A.ID = E.UserID 
    WHERE A.ID IN (
      SELECT A.UserID 
      FROM Friends A 
      INNER JOIN Sessions S ON A.FriendID = S.UserID 
      WHERE S.SID = "1234" 
       AND Deleted = 'No' 
      ) 
    ) C 
LEFT JOIN (
    SELECT DISTINCT B.ID 
     ,B.NAME 
     ,F.Hidden 
    FROM Users B 
    INNER JOIN Friends F ON B.ID = F.FriendID 
    WHERE B.ID IN (
      SELECT A.FriendID 
      FROM Friends A 
      INNER JOIN Sessions S ON A.UserID = S.UserID 
      WHERE S.SID = "1234" 
       AND Deleted = 'No' 
      ) 
    ) D ON C.ID = D.ID 

UNION 

    DISTINCT 
SELECT * 
    ,CASE 
     WHEN C.ID IS NULL 
      THEN "Request Sent" 
     ELSE "Friends" 
     END AS STATUS 
FROM (
    SELECT DISTINCT A.ID 
     ,A.NAME 
     ,E.Hidden 
    FROM Users A 
    INNER JOIN Friends E ON A.ID = E.UserID 
    WHERE A.ID IN (
      SELECT A.UserID 
      FROM Friends A 
      INNER JOIN Sessions S ON A.FriendID = S.UserID 
      WHERE S.SID = "1234" 
       AND Deleted = 'No' 
      ) 
    ) C 
RIGHT JOIN (
    SELECT DISTINCT B.ID 
     ,B.NAME 
     ,F.Hidden 
    FROM Users B 
    INNER JOIN Friends F ON B.ID = F.FriendID 
    WHERE B.ID IN (
      SELECT A.FriendID 
      FROM Friends A 
      INNER JOIN Sessions S ON A.UserID = S.UserID 
      WHERE S.SID = "1234" 
       AND Deleted = 'No' 
      ) 
    ) D ON C.ID = D.ID 

解释系统的基本方式是,如果两个用户是朋友,再有就是在数据库中两个记录。一个从第一个用户到第二个,另一个从第二个用户到第一个。

如果存在从当前用户到另一个用户的记录,并且如果有从一个用户到当前用户的记录已收到好友请求,则发送好友请求。

这里是它如何工作的范恩图:

Venn Diagram

SQL小提琴 - http://sqlfiddle.com/#!2/c5587/1

+0

这将是更具可读性,如果你能缩进你的申请。 –

+1

尝试使用http://poorsql.com/ – aldux

+0

@AnthonyRaymond我已经编辑了我的代码 –

回答

0

的Sql小提琴:http://sqlfiddle.com/#!2/06e08/68/0

这回Friends and Request Sent

SELECT 
    f.FriendID, 
    u.Name, 
    f.Hidden, 
    CASE 
    WHEN reqs.FriendID IS NULL 
     THEN "Request Sent" 
    WHEN reqs.FriendID = f.UserID 
     THEN "Friends" 
    END AS Status 
FROM 
    Friends AS f 
    INNER JOIN 
    Sessions AS s 
    ON f.UserId = s.UserID 
    INNER JOIN 
    Users AS u 
    ON u.ID = f.FriendID 
    LEFT JOIN 
    Friends AS reqs 
    ON reqs.FriendID = f.UserID 
     AND reqs.UserID = f.FriendID 
WHERE 
    s.SID = "sid1" 

如果您还想Request Received,追加这样的:

UNION 

SELECT 
    f.UserID, 
    u.Name, 
    f.Hidden, 
    "Request Received" AS Status 
FROM 
    Friends AS f 
    INNER JOIN 
    Sessions AS s 
    ON f.FriendID = s.UserID 
    INNER JOIN 
    Users AS u 
    ON u.ID = f.UserID 
WHERE 
    f.UserID NOT IN 
    (
     SELECT 
     ff.FriendID 
     FROM 
     Friends AS ff 
     INNER JOIN 
      Sessions AS ss 
      ON ff.UserID = ss.UserID 
     WHERE ss.SID = "sid1" 
    ) 
    AND s.SID = "sid1" 

无法弄清楚如何优化的最后一部分。由于这是一个自我加入,这是一个该死的心灵扭曲者。

我明白这不是你所期望的,但我不能让所有的SID的车程,但这一要求应该比您目前使用的一个快