Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
匹配MySQL表中的用户操作:每个关闭都应该匹配给定用户的上一个打开_Mysql_Sql - Fatal编程技术网

匹配MySQL表中的用户操作:每个关闭都应该匹配给定用户的上一个打开

匹配MySQL表中的用户操作:每个关闭都应该匹配给定用户的上一个打开,mysql,sql,Mysql,Sql,我有一个用户操作表,每个操作都有一个关联的用户、一个类型和一个时间戳。下面是一个简化的示例: TABLE USER_ACTIONS ------------------------ USER | TYPE | TIMESTAMP ------------------------ a | OPEN | 0 b | OPEN | 1 a | CLOSE | 2 a | OPEN | 3 b | CLOSE | 4 a | CLOSE | 4 a |

我有一个用户操作表,每个操作都有一个关联的用户、一个类型和一个时间戳。下面是一个简化的示例:

TABLE USER_ACTIONS
------------------------
USER | TYPE  | TIMESTAMP
------------------------
a    | OPEN  | 0
b    | OPEN  | 1
a    | CLOSE | 2
a    | OPEN  | 3
b    | CLOSE | 4
a    | CLOSE | 4
a    | OPEN  | 5  <-- "orphaned" OPEN, with no corresponding CLOSE. Should be ignored.
c    | OPEN  | 3
c    | CLOSE | 5
a    | OPEN  | 6
a    | CLOSE | 8
我不在乎点什么菜

我知道这是可以通过编程实现的,但是可以通过一些聪明的SQL实现吗

更新:

要以编程方式执行此操作,总体思路是

选择所有关闭操作,按时间戳降序排列。 对于该列表中的每个用户,请尝试查找同一用户以前执行的打开操作。将时间戳限制在关闭操作时间戳之前,按时间戳DESC对结果进行排序,并将其限制为1。 对于该对,计算时间差,并输出结果。 下面是一些伪代码,但我真的希望SQL能够巧妙地做到这一点:

for each CLOSE_ACTION IN ("SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS WHERE TYPE='CLOSE' ORDER BY TIMESTAMP DESC;") {
    OPEN_ACTION = "SELECT USER, TYPE, TIMESTAMP FROM USER_ACTIONS
                   WHERE TYPE='OPEN'
                   AND USER='<CLOSE_ACTION.USER>'
                   AND TIMESTAMP='<CLOSE_ACTION.TIMESTAMP>'
                   ORDER BY TIMESTAMP DESC
                   LIMIT 1";
    if OPEN_ACTION != empty/null then {
        print CLOSE_ACTION.USER, CLOSE_ACTION.TIMESTAMP - OPEN_ACTION.TIMESTAMP;
    }
}
尝试:


假定每次打开都有一个匹配的关闭。

这将获取每个关闭事件,并将其与前一个事件匹配,如果且仅当前一个事件是打开的

SELECT
  OPEN.user,
  OPEN.transaction_time
  CLOSE.transaction_time
FROM
  user_actions as CLOSE
INNER JOIN
  user_actions as OPEN
    ON  OPEN.user = CLOSE.user
    AND OPEN.transaction_time = (SELECT MAX(transaction_time) FROM user_action
                                 WHERE user = CLOSE.user
                                 AND transaction_time < CLOSE.transaction_time
                                 AND type='OPEN')
WHERE
    CLOSE.type = 'CLOSE'

下面的查询适用于提出的问题。我已经在我的本地机器上执行了它,它似乎工作得很好

select u1.user_name ,u2.timestamp- max(u1.timestamp) difference
from user_actions u1,user_actions u2 
where u1.type = 'OPEN' and 
u2.type = 'CLOSE' and
u1.timestamp <u2.timestamp and u1.user_name = u2.user_name
group by (u1.user_name , u2.timestamp);

您知道吗,您总是将“关闭”与“打开”关联起来?或者用户的顺序可以是打开、打开、关闭、打开、打开、关闭、关闭等?如果数据不完全干净,您知道如何处理此类情况吗?忽略重复的打开,但将关闭视为真正的关闭,例如打开,关闭?好问题:不幸的是,并不是每个打开都有一个关闭。我将更新我的表以反映这一点。对于这些情况,我只希望忽略孤立的打开,而不计算。根据您的示例,如果模式为打开、关闭、关闭,那么应该忽略哪个关闭?我的回答目前忽略了第二次关闭,并且符合您描述的其余部分。对于同一用户的打开、关闭、关闭,忽略后一次关闭是正确的。开,开,关这更复杂。第二个打开应该与关闭匹配,第一个被忽略。。。所以我认为这也是正确的。u.timestamp>a.timestamp?这看起来非常非常接近,但我无法让它正常工作。我要继续摆弄它。一旦你的答案生效,我可能会对其进行编辑。注意,编辑后,这会改变打开、关闭、关闭的情况下的行为,现在两个关闭引用都被使用,并且都返回到同一个打开位置。没关系。在这个数据集中,我们从来没有两个开放的关闭。只有多个打开才能关闭。
SELECT
  OPEN.user,
  OPEN.transaction_time
  CLOSE.transaction_time
FROM
  user_actions as CLOSE
INNER JOIN
  user_actions as OPEN
    ON  OPEN.user = CLOSE.user
    AND OPEN.transaction_time = (SELECT MAX(transaction_time) FROM user_action
                                 WHERE user = CLOSE.user
                                 AND transaction_time < CLOSE.transaction_time
                                 AND type='OPEN')
WHERE
    CLOSE.type = 'CLOSE'
select u1.user_name ,u2.timestamp- max(u1.timestamp) difference
from user_actions u1,user_actions u2 
where u1.type = 'OPEN' and 
u2.type = 'CLOSE' and
u1.timestamp <u2.timestamp and u1.user_name = u2.user_name
group by (u1.user_name , u2.timestamp);