Mysql SQL join 3个使用最新组值分组的表

Mysql SQL join 3个使用最新组值分组的表,mysql,date,join,Mysql,Date,Join,我有三张桌子。具有以下结构的用户、消息和用户分析: 用户userId-包含所有用户 message messageIdpk、useridpk、time-包含所有消息 用户分析用户分析SIDPK,用户IDFK,设备,时间- 包含在连接上收集的数据 现在我想知道每天用什么设备发送多少条消息。因此,我首先需要为每条消息收集设备桌面、iOS、Android用于发送消息的信息,具体取决于消息时间本身。这意味着我需要user_analytics.time不太确定您想要什么,但您说您的查询正在运行,您只是想要

我有三张桌子。具有以下结构的用户、消息和用户分析:

用户userId-包含所有用户 message messageIdpk、useridpk、time-包含所有消息 用户分析用户分析SIDPK,用户IDFK,设备,时间- 包含在连接上收集的数据
现在我想知道每天用什么设备发送多少条消息。因此,我首先需要为每条消息收集设备桌面、iOS、Android用于发送消息的信息,具体取决于消息时间本身。这意味着我需要user_analytics.time不太确定您想要什么,但您说您的查询正在运行,您只是想要一种高效的方式。所以你一定要试试这个,让我知道它是否有效

select  date_format(m.time,'%Y-%m-%d') as date,
        count(*) as message_count,
        ua.device, max(ua.user_analyticsId)
from    message m
        INNER JOIN
        user u ON
        m.userId = u.userId
        LEFT JOIN 
        user_analytics ua ON
        u.userId = ua.userId and       
where  
ua.time<m.time
group by 1,3;
如果需要,可以通过将整个查询放入另一个查询的from块来忽略添加的新列

select date, message_count, device from (
    select  date_format(m.time,'%Y-%m-%d') as date,
            count(*) as message_count,
            ua.device, max(ua.user_analyticsId)
    from    message m
            INNER JOIN
            user u ON
            m.userId = u.userId
            LEFT JOIN 
            user_analytics ua ON
            u.userId = ua.userId and       
    where  
    ua.time<m.time
    group by 1,3) A ;

没有必要加入用户表,所以您可以像这样简化代码:

select  date_format(m.time,'%Y-%m-%d') as date,
        count(*) as message_count,
        ua.device
from    message m,
        left join user_analytics ua on (
            m.userId = ua.userId and
            ua.user_analyticsId = ( select max(user_analyticsId) 
                                from    user_analytics
                                where   userId = m.userId and
                                        time < m.time))
group by 1,3;
我猜您最初的目的是将消息除以设备上的连接时间,所以将消息和连接记录按时间序列一起排序,然后您可以得到最后一次连接使用的设备

我认为这种方法将非常有效,因为100k+3k排序将比3k*100k*100k联接操作快得多


一项测试。

那么,随着数据集的增长,这项测试的效果如何

SELECT DATE(message_time) dt
     , b.device
     , COUNT(*)
  FROM 
     (
       SELECT m.id message_id
            , m.userid
            , m.time message_time
            , MAX(um.time) device_time
         FROM messages m
         JOIN user_analytics um
           ON um.userid = m.userid
          AND um.time <= m.time
        GROUP 
           BY m.id
      ) a
  JOIN user_analytics b
    ON b.userid = a.userid
   AND b.time = a.device_time
 GROUP
    BY DATE(message_time)
     , b.device;

在我回答这个问题之前,我需要你解决一些含糊不清的问题。如果您现在只想知道每天用什么设备发送多少条消息,那么您的查询似乎无法回答这个问题。你能不能更明确一点,你想得到什么样的数据?接下来,什么是用户分析?时间使用一个不相关的子查询,下面的答案看起来不错,但是更多的帮助考虑下面的简单的两步过程:1。如果您还没有这样做,请提供适当的DDL和/或SQLFIDLE,以便我们可以更轻松地复制问题。2.如果您还没有这样做,提供一个与步骤1中提供的信息相对应的所需结果集。该结果集的速度比我的快100倍:并生成所需结果?@草莓:是的,现在需要0.7秒,因此感觉比20秒快100倍,我想知道当数据增长时它将如何运行。我将感谢纠正和改进以上查询的信息性评论如果您的查询在having子句中返回错误代码1054,未知列ua.user\U analyticsId。多亏您的努力,但它并没有返回所需的结果,而且在我的100k数据上也需要15秒。我添加了一个sql FIDLE来演示所需的结果ICE解决方案thx,当数据增长时,你是否发现排序有问题?分析表每年增长10万?我认为历史数据永远不会改变。因此,没有必要使用这些历史数据,只需将结果扩展到message table.Thx中即可获得解决方案。它的工作原理是,没有设备信息的消息应该显示为device:null,正如您在my fiddle中看到的那样。我认为将“加入用户分析um”改为“左加入用户分析um”可以解决这个问题。我在100k上试过,查询需要15秒。是的-在这个例子中正确连接-但是你可以很容易地交换查询的两个部分。分析表中关于用户ID和时间的索引非常有用
select  date_format(m.time,'%Y-%m-%d') as date,
        count(*) as message_count,
        ua.device
from    message m,
        left join user_analytics ua on (
            m.userId = ua.userId and
            ua.user_analyticsId = ( select max(user_analyticsId) 
                                from    user_analytics
                                where   userId = m.userId and
                                        time < m.time))
group by 1,3;
select  date_format(t2.time,'%Y-%m-%d') as date,
        count(*) as message_count,
        t2.last_device
from    
    (select 
      @device := 
          if(@uid = userid,
             if(tbl = 'm' ,@device, device),
             if(@uid := userid,device,device)) as last_device
      ,t1.*
      from 
          (select @device := '' , @uid :=0) as t0
      join
          (select 'ua' as tbl,userid,time,device from user_analytics
           union all
           select 'm' as tbl,userid,time,null as device from messages
          ) as t1
      order by userid,time
    ) as t2
where tbl='m'
group by 1,3;
SELECT DATE(message_time) dt
     , b.device
     , COUNT(*)
  FROM 
     (
       SELECT m.id message_id
            , m.userid
            , m.time message_time
            , MAX(um.time) device_time
         FROM messages m
         JOIN user_analytics um
           ON um.userid = m.userid
          AND um.time <= m.time
        GROUP 
           BY m.id
      ) a
  JOIN user_analytics b
    ON b.userid = a.userid
   AND b.time = a.device_time
 GROUP
    BY DATE(message_time)
     , b.device;