如何根据当前事件和下一个事件来确定操作的持续时间?

huangapple go评论58阅读模式
英文:

SQL How to determine the duration of the action based on the current and next event?

问题

我有一个包含两列的表格:动作开始时间和动作名称。

时间 动作
2023-07-27 04:52:00.000 跑步
2023-07-27 04:55:00.000 散步
2023-07-27 04:59:00.000 散步
2023-07-27 05:01:00.000 坐着
2023-07-27 05:06:00.000 散步
2023-07-27 05:10:00.000 跑步

我需要知道每个动作的持续时间:开始时间和结束时间。开始时间是已知的动作时间。
但是如何确定结束时间呢?也就是说,下一个动作的开始时间与当前动作不同的时间点?

以"散步"动作为例:

开始时间 结束时间
2023-07-27 04:55:00.000 2023-07-27 05:01:00.000
2023-07-27 05:06:00.000 2023-07-27 05:10:00.000
英文:

I have a table with two columns: the action start time and the name of action.

time action
2023-07-27 04:52:00.000 running
2023-07-27 04:55:00.000 walking
2023-07-27 04:59:00.000 walking
2023-07-27 05:01:00.000 sitting
2023-07-27 05:06:00.000 walking
2023-07-27 05:10:00.000 running

I need to know the duration of the action: start and end time. The start time is the time of the action, which is already known.
But how to know the end time? That is, the beginning of the next action different from the current one?

Example for the action "walking"

time_start time_end
2023-07-27 04:55:00.000 2023-07-27 05:01:00.000
2023-07-27 05:06:00.000 2023-07-27 05:10:00.000

答案1

得分: 2

请参考下面的更正版本。这个版本假设每个动作都是唯一的。

我认为你可以使用lag函数来实现你的目标。

select 
    action,
    time as time_start,
    lag(time, -1) over(order by time) as time_end
from <table_name>

在这种情况下,最后一行的time_end将等于NULL,我认为这是正确的,因为它还不知道。

**编辑:**根据@Tim Biegeleisen的备注,这是基于他的工作更新的答案。然而,它正确地找到了相同连续动作的time_end值。

WITH data AS (
    SELECT '2023-07-27 04:52:00.000' AS time, 'running' AS action UNION ALL
    SELECT '2023-07-27 04:53:00.000', 'running' UNION ALL
    SELECT '2023-07-27 04:55:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 04:59:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 05:01:00.000', 'sitting' UNION ALL
    SELECT '2023-07-27 05:06:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 05:10:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 05:12:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 05:15:00.000', 'walking' UNION ALL
    SELECT '2023-07-27 05:20:00.000', 'running' 
),
withLag AS (
    SELECT 
        action,
        time AS start_time,
        LAG(time) OVER (ORDER BY time desc) AS next_time,
        ROW_NUMBER() OVER (ORDER BY time) AS row_num,
        ROW_NUMBER() OVER (PARTITION BY action ORDER BY time) AS group_num
    FROM data
)
SELECT action, min(start_time) as time_start, max(next_time) as time_end
FROM withLag
GROUP BY action, row_num - group_num
order by time_start

结果如下所示:

如何根据当前事件和下一个事件来确定操作的持续时间?

英文:

Please see the corrected version underneath. This one assumes that each action is unique.
> I think you could use the lag function to achieve your goal.
>
> select
> action,
> time as time_start,
> lag(time, -1) over(order by time) as time_end
> from <table_name>
>
> In this case the time_end for the last row will be equal to NULL,
> which I think is correct, as it isn't known yet.

EDIT: After the remark from @Tim Biegeleisen, this is the updated answer, built upon his work. However, it correctly finds the time_end value for groups of the same, consecutive actions.

WITH data AS (
    SELECT &#39;2023-07-27 04:52:00.000&#39; AS time, &#39;running&#39; AS action UNION ALL
    SELECT &#39;2023-07-27 04:53:00.000&#39;, &#39;running&#39; UNION ALL
    SELECT &#39;2023-07-27 04:55:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 04:59:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 05:01:00.000&#39;, &#39;sitting&#39; UNION ALL
    SELECT &#39;2023-07-27 05:06:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 05:10:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 05:12:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 05:15:00.000&#39;, &#39;walking&#39; UNION ALL
    SELECT &#39;2023-07-27 05:20:00.000&#39;, &#39;running&#39; 
),
withLag AS (
    SELECT 
        action,
        time AS start_time,
        LAG(time) OVER (ORDER BY time desc) AS next_time,
        ROW_NUMBER() OVER (ORDER BY time) AS row_num,
        ROW_NUMBER() OVER (PARTITION BY action ORDER BY time) AS group_num
    FROM data
)
SELECT action, min(start_time) as time_start, max(next_time) as time_end
FROM withLag
GROUP BY action, row_num - group_num
order by time_start

As a result we achieve the expected outcome:

如何根据当前事件和下一个事件来确定操作的持续时间?

答案2

得分: 1

使用行号差异方法,我们可以尝试以下代码:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY time) rn1,
              ROW_NUMBER() OVER (PARTITION BY action ORDER BY time) rn2
    FROM yourTable
)

SELECT MIN(time) AS time_start,
       MAX(time) AS time_end,
       action
FROM cte
GROUP BY rn1 - rn2, action
ORDER BY MIN(time);

以下是来自下面演示链接的屏幕截图:

如何根据当前事件和下一个事件来确定操作的持续时间?

Demo

英文:

Using the difference in row numbers method we can try the following:

<!-- language: sql -->

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY time) rn1,
              ROW_NUMBER() OVER (PARTITION BY action ORDER BY time) rn2
    FROM yourTable
)

SELECT MIN(time) AS time_start,
       MAX(time) AS time_end,
       action
FROM cte
GROUP BY rn1 - rn2, action
ORDER BY MIN(time);

如何根据当前事件和下一个事件来确定操作的持续时间?

<h2>Demo</h2>

huangapple
  • 本文由 发表于 2023年7月27日 16:57:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76778105.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定