2016-07-14 43 views
-1

我已经存储发送给用户的信息表,布局如下选择前N个消息按每个用户接收

id (auto-incrementing) | message_id | user_id | datetime_sent 

我试图找到前N MESSAGE_ID的每个用户已收到,但我完全卡住了。我可以在每个用户的基础上(在查询中定义用户ID时)轻松完成此操作,但不适用于全部用户。

注意事项:

  • 许多用户都可以得到相同的MESSAGE_ID
  • 消息ID的顺序不被发送
  • 这仅仅是一个读(即我们可以消息200之前发送消息400) MySQL数据库

编辑:关于第二个想法,我删除这一点,但增加了它放回因为有人还跟它

工作

最终目标是查看百分之多少用户打开了他们收到的前N条消息之一。

的那台打开这个样子的:

user_id | message_id | datetime_opened 
+0

为什么不创建一个在db中插入消息日期的日期时间列? – Santiago

+0

@Santiago time_sent的列实际上是一个日期时间,而不仅仅是时间。编辑帖子澄清。另外,正如笔记中提到的那样,它是一个只读数据库。 – Brandon

+0

您是否要求提供* all *用户的百分比,或者只有那些收到至少一条消息的用户? – trincot

回答

0

这是一个未经测试的答案,原来的问题(有2个表和条件对第5):

SELECT DISTINCT user_id 
FROM ( 
      SELECT  om.user_id, 
         om.message_id, 
         count(DISTINCT sm2.message_id) messages_before 
      FROM  opened_messages om 
      INNER JOIN sent_messages sm 
        ON om.user_id = sm.user_id 
        AND om.message_id = sm.message_id 
      LEFT JOIN sent_messages sm2 
        ON om.user_id = sm2.user_id 
        AND sm2.datetime_sent < sm.datetime_sent 
      GROUP BY om.user_id, 
         om.message_id 
      HAVING  messages_before < 5 
     ) AS base 

子查询中加入sm2来计算发送给同一用户的先前消息的数量,然后having子句确保发送的消息少于5个。对于同一用户,可能会有多条消息(最多5条),该外部查询仅列出符合条件的唯一用户。

+0

这真棒!我非常需要。你等不及要进一步研究你的答案。 – Brandon

0

为了得到第N(在这里2)信息时,请

SELECT 
    user_id 
    , message_id 
FROM (
    SELECT 
    user_id 
    , message_id 
    , id 
    , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
     (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
    FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
    JOIN (SELECT @cnt := 0) c 
    JOIN (SELECT @user_id := 0) u 
) R 
WHERE rank < 3 
ORDER BY user_id, id 
; 

它采用了RANK替代品,从@Seaux response衍生的MySQL是否有Oracle的“解析函数相当于”?

将其扩展到你原来的问题,只需添加相应的计算:

SELECT 
    COUNT(DISTINCT MO.user_id) * 100/
    (SELECT COUNT(DISTINCT user_id) 
    FROM (
     SELECT 
     user_id 
     , message_id 
     , id 
     , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
      (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
     FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
     JOIN (SELECT @cnt := 0) c 
     JOIN (SELECT @user_id := 0) u 
    ) R2 
    WHERE rank < 3 
    ) AS percentage_who_read_one_of_the_first_messages 
FROM MessageOpened MO 
JOIN 
    (SELECT 
     user_id 
     , message_id 
    FROM (
     SELECT 
     user_id 
     , message_id 
     , id 
     , (CASE WHEN @user_id != user_id THEN @rank := 1 ELSE @rank := @rank + 1 END) AS rank, 
      (CASE WHEN @user_id != user_id THEN @user_id := user_id ELSE @user_id END) AS _ 
     FROM (SELECT * FROM MessageSent ORDER BY user_id, id) T 
     JOIN (SELECT @cnt := 0) c 
     JOIN (SELECT @user_id := 0) u 
    ) R 
    WHERE rank < 3) MR 
    ON MO.user_id = MR.user_id 
    AND MO.message_id = MR.message_id 
; 

随着MySQL的无热膨胀系数,并且在只读数据库中 - 我看到绕在上面的查询没有办法在声明中两次。

看到它的行动:SQL Fiddle

请评论如果和因为这需要调整/进一步的细节。