MySQL 删除子查询中的重复子句

Posted

技术标签:

【中文标题】MySQL 删除子查询中的重复子句【英文标题】:MySQL Remove repeating clauses in subqueries 【发布时间】:2014-07-09 05:53:47 【问题描述】:

我正在尝试简化我的查询,使其只包含一次会话 ID (SID)。

Users表的抽象结构是:

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

Friends 表具有如下抽象结构:

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

Sessions表的抽象结构:

+----+-----------------+-----+
| 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

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

如果当前用户有记录到另一个用户,则发送好友请求,如果一个用户到当前用户有记录,则收到好友请求。

这是一个工作原理的范恩图:

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

【问题讨论】:

如果您可以缩进您的请求,它将更具可读性。 尝试使用poorsql.com @AnthonyRaymond 我已经编辑了我的代码 你能发布一个带有一些数据的 sqlfiddle 供我们使用吗?还有你想要的输出是什么? @JohnRuddell 我已经为问题添加了一个 sql fiddle 链接 【参考方案1】:

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"

不知道如何优化最后一部分。因为它是一个 SELF JOIN,所以它是一个该死的脑筋急转弯。

我知道这不是您所期望的,但是,我无法获得所有 SID,但此请求应该比您当前使用的请求更快

【讨论】:

以上是关于MySQL 删除子查询中的重复子句的主要内容,如果未能解决你的问题,请参考以下文章

mysql 子句子查询连接查询

MySQL:删除子查询返回的行

MySql VIEW 删除 FROM 条件下的子查询

mysql 删除可以用子查询吗

Mysql中的子查询等操作

优化包含重复查询作为子查询的 MySQL 查询?