匹配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);