sql - MySQL 嵌套聚合查询,选择特定的中间项

标签 sql mariadb window-functions mariadb-10.5

这是我的事件表。

activities
+----+---------+----------+-----------------+
| id | user_id | activity |    log_time     |
+----+---------+----------+-----------------+
|  6 |       1 | start    | 12 Oct, 1000hrs |
|  2 |       1 | task     | 12 Oct, 1010hrs |
|  7 |       1 | task     | 12 Oct, 1040hrs |
|  3 |       1 | start    | 12 Oct, 1600hrs |
|  1 |       1 | task     | 12 Oct, 1610hrs |
|  9 |       1 | start    | 14 Oct, 0800hrs |
| 10 |       1 | start    | 16 Oct, 0900hrs |
|  4 |       1 | task     | 16 Oct, 0910hrs |
|  8 |       2 | start    | 12 Oct, 1000hrs |
|  5 |       2 | task     | 12 Oct, 1020hrs |
+----+---------+----------+-----------------+

我需要用户在所有 session 中花费的总时间。每个 session 在一天内发生,并包括一个“开始”和多个“任务”(在下一个 session 通过“开始”启动之前)。一次 session 时长=上一个任务-开始[时间戳差]

output
+---------+------------+------------------------------------------------+
| user_id | total_time |       This is explanation (not a column)       |
+---------+------------+------------------------------------------------+
|       1 |         60 | 12_Oct[40+10] + 14_Oct[0] + 16_Oct[10] = 60min |
|       2 |         20 | 12_Oct[20]  = 20min                            |
+---------+------------+------------------------------------------------+

我无法弄清楚如何获取 session 中的最后一个任务。我已经尝试过基本的聚合和连接查询 - 但它不起作用。

作为一种方法,我认为我真正需要的是以某种方式获取最后一列(/session_group 下面),然后我可以聚合并获取最大/最小时间戳之间的差异。

+----+---------+----------+-----------------+---------------+
| id | user_id | activity |    log_time     | session_group |
+----+---------+----------+-----------------+---------------+
|  6 |       1 | start    | 12 Oct, 1000hrs |             1 |
|  2 |       1 | task     | 12 Oct, 1010hrs |             1 |
|  7 |       1 | task     | 12 Oct, 1040hrs |             1 |
|  3 |       1 | start    | 12 Oct, 1600hrs |             2 |
|  1 |       1 | task     | 12 Oct, 1610hrs |             2 |
|  9 |       1 | start    | 14 Oct, 0800hrs |             3 |
| 10 |       1 | start    | 16 Oct, 0900hrs |             4 |
|  4 |       1 | task     | 16 Oct, 0910hrs |             4 |
|  8 |       2 | start    | 12 Oct, 1000hrs |             5 |
|  5 |       2 | task     | 12 Oct, 1020hrs |             5 |
+----+---------+----------+-----------------+---------------+

请告诉我是否可以通过 sql (MySQL) 获得所需的输出以及如何进行?或者是否有必要通过 JavaScript 循环数据?

下面是表的 MySQL 查询:

create table activities (
  id INT NOT NULL, 
  user_id INT NULL, 
  activity VARCHAR(45), 
  log_time DATETIME NOT NULL DEFAULT NOW(),
  PRIMARY KEY(id))
 ENGINE = InnoDB;    
 
insert into activities
    (id, user_id, activity, log_time) 
values
    (6,1,'start', '2021-10-12 10:00:00'), 
    (2,1,'task' , '2021-10-12 10:10:00'), 
    (7,1,'task' , '2021-10-12 10:40:00'), 
    (3,1,'start', '2021-10-12 16:00:00'), 
    (1,1,'task',  '2021-10-12 16:10:00'), 
    (9,1,'task',  '2021-10-14 08:00:00'), 
    (10,1,'start','2021-10-16 09:00:00'), 
    (4,1,'task',  '2021-10-16 09:10:00'), 
    (8,2,'start', '2021-10-12 10:00:00'), 
    (5,2,'task',  '2021-10-12 10:20:00');

最佳答案

您可以使用SUM()窗口函数为每个 session 分配一个数字,然后聚合:

SELECT DISTINCT user_id,
       SUM(TIMESTAMPDIFF(MINUTE, MIN(log_time), MAX(log_time))) OVER (PARTITION BY user_id) total_time 
FROM (
  SELECT *, SUM(activity = 'start') OVER (PARTITION BY user_id, DATE(log_time) ORDER BY log_time) grp
  FROM activities
) t
WHERE grp > 0
GROUP BY user_id, DATE(log_time), grp;

请参阅demo .

关于sql - MySQL 嵌套聚合查询,选择特定的中间项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69787415/

相关文章:

python - Django ORM 无法识别嵌套 ON 语句中的具体继承

mysql - 在 SQL SUM expr 中可以做什么?

mysql 8 窗口函数错误的结果

sql - 为什么添加一个窗口函数会使这个查询变得如此缓慢?

mysql - 通过 SQLmap 进行 SQL 注入(inject) - UNION ALL 注入(inject)如何工作?

php - 如果另一个表 ID 匹配则更新一个表

php - 用php生成xls文件时设置字符编码

MySQL AVG 函数给出的小数比预期多

mysql - 应用程序集群中同步作业的最佳实践

MySQL - 如何根据单列查找重复行?