2013-09-28 29 views
0

我正在建立一个MySQL查询,但我卡住了...(我每分钟记录) 我有3个表。日志,log_field,log_value。Mysql查询跳过行并检查状态变化

logs -> id, create_time 
log_value -> id, log_id,log_field_id,value 
log_field -> id, name (one on the entries is status and username) 

的状态的值可以是在线,离线和闲置...

我想看到的是从我的查询是: 当我的日志有人从状态的变化,我想与create_time,用户名,状态行。

因此,对于给定的用户,我希望我的查询跳过行直到出现新的状态... 而且我需要能够放置忽略状态更改的时间间隔。

有人可以帮忙吗?

+0

你可以发布一些示例数据,并显示你希望从中得到什么......我很确定我理解,但示例数据会有所帮助。不要使用制表符将列和空格对齐。并且一旦所有数据排列整齐,突出显示整个分段并单击花括号的按钮,以便S/O将其视为格式化的代码,将单词作为原始问题的一部分包装文本。 – DRapp

回答

0

尽管您没有任何区别您帖子中列出的实际“用户”(例如用户ID)的内容,以及如果您有两个“John Smith”名称会发生​​什么情况。

首先,介绍MySQL @variables。您可以将它们视为在查询处理行时运行的内联程序。您可以创建变量,然后在每行处理完毕后将其更改,按照相同的顺序进行更改,因为字段选择中的:=赋值是重要的。我会很快回覆。

第一个前提。您有一个可以/可以记录的所有可能字段的字段值表。其中有两个存在......一个是用户名,另一个是您正在查看日志的状态已更改。我不知道这些内部“ID”号码是什么,但它们必须是每个现有表格的固定值。在我的场景中,我假设字段ID = 1是用户的名称,字段ID 2 =状态列...否则,您需要两个更多的连接才能获取字段表,以确认哪个字段是您的字段通缉。很明显,我的“ID”字段值与您的生产表不匹配,所以请相应地更改这些值。

这里的查询......

select FinalAlias.* 
from (
select 
     PQ.*, 
     if(@lastUser = PQ.LogUser, 1, 0) as SameUser, 
     @lastTime := if(@lastUser = PQ.LogUser, @lastTime, @ignoreTime) as lastChange, 
     if(PQ.create_time > @lastTime + interval 20 minute, 1, 0) as BeyondInterval, 
     @lastTime := PQ.create_time as chgTime, 
     @lastUser := PQ.LogUser as chgUser 
    from 
     (select 
       ByStatus.id, 
       l.create_time, 
       ByStatus.Value LogStatus, 
       ByUser.Value LogUser 
      from 
       log_value as ByStatus 
       join logs l 
        on ByStatus.log_id = l.id 
       join log_value as ByUser 
        on ByStatus.log_id = ByUser.log_id 
        AND ByUser.log_field_id = 1 
      where 
       ByStatus.log_field_id = 2 
      order by 
       ByUser.Value, 
       l.create_time) PQ, 
     (select @lastUser := '', 
       @lastTime := now(), 
       @ignoreTime := now()) sqlvars 
     ) FinalAlias 
    where 
      SameUser = 1 
     and BeyondInterval = 1 

现在,这是怎么回事。最内层查询(结果别名PQ代表“PreQuery”)只是要求field_id = 2(状态列)存在的所有日志值。从该日志条目中,转到日志表的创建时间...在我们处于该状态时,将AGAIN加入到同一个日志ID的日志值表中,但是这次也查找field_id = 1,以便我们可以获取用户名。

完成后,获取所有按用户预先排序的日志ID,创建时间,状态值和用户名,并按时间顺序排列。这是关键的一步。数据必须按用户/时间预先组织,以将给定用户的“最后”时间与他们的日志状态更改的“下一次”时间进行比较。

现在,MySQL @variables。将prequery加入另一个给出“sqlvars”查询别名的@variables选择。这将预先初始化变量fo @lastUser,@lastTime和@ignoreTime。现在,看看我在场上列表,经由部分

 if(@lastUser = PQ.LogUser, 1, 0) as SameUser, 
     @lastTime := if(@lastUser = PQ.LogUser, @lastTime, @ignoreTime) as lastChange, 
     if(PQ.create_time > @lastTime + interval 20 minute, 1, 0) as BeyondInterval, 
     @lastTime := PQ.create_time as chgTime, 
     @lastUser := PQ.LogUser as chgUser 

这就像在做一个循环下面的伪码每个记录(这已经是连续由同一人及彼等各自的日志时间排序做

FOR EACH ROW IN RESULT SET 
    Set a flag "SameUser" = 1 if the value of the @lastUser is the same 
    as the current person record we are looking at 

    if the last user is the same as the previous record 
     use the @lastTime field as the "lastChange" column 
    else 
     use the @ignore field as the last change column 

    Now, build another flag based on the current record create time 
    and whatever the @lastTime value is based on a 20 minute interval. 
    set it to 1 if AT LEAST the 20 minute interval has been meet. 

    Now the key to the cycling the next record. 
    force the @lastTime = current record create_time 
    force the @lastUser = current user 
END FOR LOOP 

所以,如果你有以下作为prequery的结果...(留下日期部分off)为比尔

create status user sameuser lastchange 20minFlag carry to next row compare 
07:34 online Bill  0  09:05  0   07:34 Bill 
07:52 idle  Bill  1  07:34  0   07:52 Bill 
08:16 online Bill  1  07:52  1   08:16 Bill 
07:44 online Mark  0  09:05  0   07:44 Mark 
07:37 idle  Monica 0  09:05  0   07:37 Monica 
08:03 online Monica 1  07:37  1   08:03 Monica 

通知第一个记录。因为在他之前没有人,所以标志相同的用户= 0。最后一次更改是9:05(创建sqlvars变量时通过NOW()),但是请查看“carry to next row compare”。在根据需要比较当前行之后,这将设置@lastTime和@lastUser。

Bill的下一行。它看到他与上一个用户的上一行相同,所以SameUser标志设置为1.现在我们知道,我们有一个很好的“上次时间”来比较当前记录“创建时间”。因此,从7点34分到7点52分是18分钟,比我们20分钟的时间间隔短20分钟,因此我们保留了现在的7:52和比尔的第三排。

比尔的第三排。仍为同一用户(标志= 1),最后更改为7:52而不是现在8:16,我们有24分钟...所以20分钟标志= 1。保留8:16和Bill作为下一行。

马克的第一行。自上次用户为Bill以来,Same User = 0。使用相同的9:05忽略时间并且不关心20分钟的标志,但是现在保存7:44并且标记为下一行比较。

对莫妮卡。与Mark不同,所以SameUser = 0等与Bill完成相似。

所以,现在我们已经考虑了所有的块和行。现在,将所有这些包装起来并作为查询的“FinalAlias”,我们所做的就是为“SameUser = 1”应用WHERE子句并且已经达到“20分钟标记”。

您可以根据需要去掉最后一列的列表,并删除where子句查看结果,但一定要为name/create_time添加一个外部ORDER BY子句,以查看类似的模式,就像我在这里一样。