带有子句的TIMESTAMPDIFF

时间:2016-01-25 15:13:14

标签: php mysql

MySQL查询有点问题:

表就像这样

id  timedate            user  action
1   2010-01-01 10:01:01 AB991 login
2   2010-01-01 12:01:01 AB991 logout
3   2010-01-01 14:01:01 AB991 login
4   2010-01-01 18:01:01 AB991 logout
5   2010-01-01 10:01:01 ZM991 login
6   2010-01-01 10:01:01 ZM991 logout
7   2010-01-02 10:01:01 AB991 login
8   2010-01-02 18:01:01 AB991 logout
9   2010-01-02 10:01:01 ZM991 login

现在,我需要一个查询或一些PHP代码来逐日计算每个用户登录和注销之间的分钟差异。 但是可能存在一些问题,例如:

  1. 可能没有注销登录
  2. 有一天我可能会有2次登录和2次注销操作。
  3. 有智能解决方案(可能只有MySQL)或者我必须使用PHP并制作代码墙吗?

2 个答案:

答案 0 :(得分:0)

可能的解决方案如下:

select id, timedate, action
from mytable
where user = 'AB991'
order by timedate

您的PHP代码将按日期获得有序列表。该算法应如下所示:

$user = 'AB991';
$stmt = $db->prepare("select id, timedate, action from mytable where user = ? order by timedate");
$stmt->execute(array($user));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$previousTime = "";
foreach ($rows as $row) {
    if ($row["action"] === "login") {
        $previousTime = strtotime($row["timedate"]);
    } else if ($row["action"] === "logout") {
        if ($previousTime === "") {
            //duplicate logout
        } else {
            //add the remaining time to the day when the user logged in
            //add the whole days passed between log in and log out
            //add the start of the last day when the user logged in
            $previousTime = "";
        }
    }
}

<强>问题

  • 用户可以单独使用不同的会话登录
  • 用户可能无法注销
  • 用户可能会使用其他会话退出

建议:我会修改表格以包含会话ID和最后一个操作。当用户执行操作时,最后一个操作的时间戳将被更新,因此您将拥有基于会话的数据,其中每一行都会说明一切,显示登录时间和上次操作时间。

答案 1 :(得分:0)

我认为这个解决方案有所帮助。作为基础每次登录由logout流动来解释这里的代码 我加入所有登录记录(排名)和所有登出记录(排名) 因此,如果一次登录将计数1并且如果由登出计数1流动,则将被选中

select
logIn. *, logOut.* ,
TIMESTAMPDIFF(MINUTE, logIn.timedate, logOut.timeDate) as howLongUserStaysInMinutes

from (SELECT @row_counter1 := 0) x,
     (SELECT @row_counter2 := 0) y,
     (select userLogs.* , @row_counter1 := @row_counter1 +1 as row 
      from userLogs 
      where userLogs.action ='login') as logIn

 left join (select * ,   @row_counter2 :=  @row_counter2 + 1 as row 
             from  userLogs 
             where  userLogs.action = 'logout') as logOut 
             on  logOut.user = logIn.user
             and ( logIn.timedate <= logOut.timedate ||   logOut.timedate is null) 
             and logIn.row = logOut.row

我从内到左进行了更改连接,所以我一次登录并且没有注销,并且从行号到按日排名所以每天都会计入登录/注销从1开始,我曾经用Microsoft SQL Server执行此操作。 让我们开始解释查询如何工作我需要的第一个数据 但首先你需要准备好以下思考的步骤:  答:我需要数据(&#39;退出记录&#39;以及&#39;登录记录&#39;)&lt; - 这里您可以应用每日选择或最大值或相同值的逻辑  B.然后我想应用条件来获取这些数据并正确过滤它 - 这里完成加入登录和注销记录,以便你可以正确匹配它们

1.我希望获得每个用户的所有登录操作,并使用变量@row_counter为每一行提供一个数字,并为每一行增加1

  select id, 
         timedate as timedate, # here you can use max() to get max login in day
         user,
         action, # action will be login since it specified at where clause
         @row_counter1 := if(@perv_day1 <> DAY( userLogs.timedate ) , 1 , @row_counter1 +1) rankedByDay
        ,@perv_day1 := if(@perv_day1 <> DAY( userLogs.timedate ) , DAY( userLogs.timedate ) ,  @perv_day1) _day
  from userLogs,
       (select  @row_counter1 :=0) x # here I define the row with 0
       (select @perv_day1 :=0) y # to track rank for each row 
  where userLogs.action ='login'
  group by user # here i group each user
          , DAY( userLogs.timedate ) # also you can group by day

出:

id  timedate            user    action  rowRankedByDay
1   2010-01-01 10:01:01 AB991   login   1
3   2010-01-01 14:01:01 AB991   login   2
5   2010-01-01 10:01:01 ZM991   login   3
7   2010-01-02 10:01:01 AB991   login   1
9   2010-01-02 10:01:01 ZM991   login   2

2.我对注销行动

也这样做
  select id, 
         timedate as timedate, # here you can use max() to get max login in day
         user,
         action, # action will be logout since it specified at where clause
         @row_counter2 := if(@perv_day2 <> DAY( userLogs.timedate ) , 1 , @row_counter1 +1) rankedByDay,
         @perv_day1 := if(@perv_day1 <> DAY( userLogs.timedate ) , DAY( userLogs.timedate ) ,  @perv_day1) _day
  from userLogs , 
       (select  @row_counter2 :=0) y # here I define the row with 0
       (select @perv_day2 :=0) y # to track rank for each row 
  where userLogs.action ='logout'
  group by user # here i group each user

out

id  timedate            user    action  rowRankedByDay
2   2010-01-01 12:01:01 AB991   logout  1
4   2010-01-01 18:01:01 AB991   logout  2
6   2010-01-01 10:01:01 ZM991   logout  3
8   2010-01-02 18:01:01 AB991   logout  1

现在我有了数据,我想加入它们,这样我就可以找到时间上的差异但是需要做些什么条件,

select TIMESTAMPDIFF(MINUTE, logIn.timedate, logOut.timeDate) as howLongUserStaysInMinutes
from logIn
left join logOut on (logOut.user =  logIn.user) # same user
              and DAY( logIn.timedate )  =  DAY( logOut.timedate ) # action at the same day
              and logIn.rowRankedByDay= logOut.rowRankedByDay # login and logout actions rows
              and ( logIn.timedate <= logOut.timedate ||   logOut.timedate is null) # login was before logout or user did not logout

很抱歉,如果这里有更多代码,;)我希望这对你有帮助。