【问题标题】:MYSQL: Find all posts between certain usersMYSQL:查找特定用户之间的所有帖子
【发布时间】:2013-11-19 21:39:12
【问题描述】:

我有两张桌子:

表消息(保存消息的创建者和消息)
id - creatorId - msg

还有一个表message_viewers(告诉谁可以读取消息msgId)
msgId - userId

如果我以用户 1 的身份创建消息并将其发送给用户 2 和用户 3,表格将如下所示:

tbl_message:  
1 - 1 - 'message'
tbl_message_viewers:  
1 - 2  
1 - 3

我想要做的是获取用户 x1...xN(任意数量的用户)之间的消息,并且只获取他们之间的消息。
(例如,如果用户是 1、2 和 3,我想要创建者为 1、2 或 3 的消息,并且用户是 2,3,创建者 = 1、1 和 3,创建者 = 2 和 1、2 creator = 3)
我对 1 和 2、2 和 3、1 和 3 之间的消息不感兴趣,而只对 3 个人之间的消息感兴趣.

我尝试了不同的方法,例如在消息 id 上连接两个表,选择 creatorId IN (X,Y) 所在的消息,然后仅获取 userId IN (X, Y) 所在的行。也许是关于对行进行分组和计数的事情,但我想不出一种可行的方法。


编辑:这里的 SQL Fiddle


http://sqlfiddle.com/#!2/963c0/1

【问题讨论】:

  • 一条消息在 tbl_message_viewers 中是否需要至少一行?
  • 是的。并且帖子的创建者不会向自己发送消息。
  • 不,是三个人的专属。

标签: mysql sql


【解决方案1】:

我认为这可能会满足您的需求:

SELECT m.*
FROM message m
INNER JOIN message_viewers mv ON m.id = mv.msgId
WHERE m.creatorId IN (1, 2, 3)
  AND mv.userId IN (1, 2, 3)
  AND NOT EXISTS (
    SELECT 1
    FROM message_viewers mv2
    WHERE mv2.msgId = mv.msgId
      AND mv2.userId NOT IN (1, 2, 3)
    )
  AND mv.userId != m.creatorId;

IN 将提供创建/可以看到的用户,mv.userId != m.creatorId 用于从 message_viewers 表中排除创建者(就像您在要求中显示的那样)。

编辑:

由于要求只在这 3 个 id 之间发送消息,我想出了以下内容:

SELECT m.id,m.creatorId,m.message
FROM message m
INNER JOIN message_viewers mv ON m.id = mv.msgId
WHERE m.creatorId IN (1, 2, 3)
  AND mv.userId IN (1, 2, 3)
  AND mv.userId != m.creatorId
  AND NOT EXISTS (
    SELECT 1
    FROM message_viewers mv2
    WHERE mv2.msgId = mv.msgId
      AND mv2.userId NOT IN (1, 2, 3)
    )
GROUP BY 1,2,3
HAVING COUNT(*) = 2;

sqlfiddle demo

【讨论】:

  • 此查询还返回所有包含 1、2 和 3 的组合,但不只返回仅由 1、2 和 3 发送和接收的消息
  • @user3010549。试试这个查询。我添加了一个不存在以排除其他观众。
  • 尝试查询时出现语法错误(似乎不喜欢 EXISTS (SELECT 1 ...
  • 对不起。我在那里有一个额外的 mv_userId。我正在删除它。
  • 这会返回在任何用户组合之间发送的所有消息,而不是严格在所有用户之间发送的消息(它可以返回仅在 1 和 2 之间或 2 或 3 之间的消息)
【解决方案2】:

用 join 和 IN() 子句试试这个

SELECT * FROM 
tbl_message m
JOIN tbl_message_viewers mv (m.id = mv.msgId )
WHERE m.creatorId IN(1,2,3) AND mv.userId IN(1,2,3)

【讨论】:

    【解决方案3】:

    听起来您可能需要BETWEEN 运算符:

    SELECT * FROM tablename WHERE fieldname BETWEEN 1 AND 10;
    -- returns fieldname 1-10
    

    但是,在这种情况下,BETWEEN 包含在内,因此您还需要指定 != 这些条件:

    SELECT * FROM tablename WHERE fieldname BETWEEN 1 AND 10 AND fieldname NOT IN (1, 10)
    -- returns fieldname 2-9
    

    http://www.w3schools.com/sql/sql_between.asp

    【讨论】:

    • 我使用了用户 1、2 和 3,但它可能在用户 1、17 和 32 之间。
    • ...WHERE fieldname BETWEEN 1 AND 17 AND fieldname BETWEEN 17 AND 32 AND fieldname NOT IN(1, 17, 32)
    【解决方案4】:

    这适用于甲骨文

    第一次加入获取我们不感兴趣的人的行数 第二个加入获取我们感兴趣的人的行数

    in 子句需要由某种动态 sql 生成 并且 number_of_people 也需要以某种方式生成。

    select msgId, count_1, count_2
      from message tm
           join ( select ty.msgId as ty_msgId, 
                         count(ty.msgId) as count_1 
                    from message_viewers ty
                   where ty.userId not in (:a,:b,:c)
                group by ty.msgId)
             on msgId = ty_msgId
           join (select tz.msgId as tz_msgId, 
                        count(tz.msgId) as count_2 
                   from message_viewers tz
                  where tz.userId in (:a,:b,:c)
                  group by tz.msgId)
             on msgId = tz_msgId
          where createrId in(:a,:b,:c)
            and count_1 = 0
            and count_2 = :number_of_people -1;   
    

    我的 sql 更喜欢这个

    select msgId, count_1, count_2
      from message tm
           left join ( select ty.msgId as ty_msgId, 
                         count(ty.msgId) as count_1 
                    from message_viewers ty
                   where ty.userId not in (:a,:b,:c)
                group by ty.msgId) as X
             on msgId = ty_msgId
           left join (select tz.msgId as tz_msgId, 
                        count(tz.msgId) as count_2 
                   from message_viewers tz
                  where tz.userId in (:a,:b,:c)
                  group by tz.msgId) as Y
             on msgId = tz_msgId
          where createrId in(:a,:b,:c)
            and (count_1 = 0 or count_1 is null)
            and count_2 = :number_of_people -1;   
    

    【讨论】:

    • 我用小提琴尝试了这个查询(见我更新的帖子),但它没有为用户 1、2 和 3 返回任何结果
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 2010-11-16
    • 2020-07-13
    • 1970-01-01
    • 2011-09-21
    • 2019-08-01
    • 1970-01-01
    相关资源
    最近更新 更多