在 SQL 中按组中的行计算时间差异
Posted
技术标签:
【中文标题】在 SQL 中按组中的行计算时间差异【英文标题】:Calculate time diff by rows in group in SQL 【发布时间】:2020-05-13 20:33:29 【问题描述】:我有一个包含用户站点访问和访问时间戳的数据集。如何按 id 对用户进行分组并计算 SQL 中用户访问之间的时间差?抱歉,对于新手问题,我是 SQL 的新手,试图构建一些报告。
我的数据集示例:
+----------+------------+---------------------+
| userID | visitID | vsitTS |
+----------+------------+---------------------+
| user01 | visit01 | 2019-05-13 01:00:00 |
| user01 | visit02 | 2019-05-13 01:10:00 |
| user02 | visit01 | 2019-05-13 01:05:00 |
| user02 | visit02 | 2019-05-13 01:10:00 |
| user02 | visit03 | 2019-05-13 01:20:00 |
| user02 | visit04 | 2019-05-13 01:30:00 |
+----------+------------+---------------------+
我需要这样的结果:
+----------+------------+---------------+
| userID | visitID | time_dif_sec |
+----------+------------+---------------+
| user01 | visit01 | 0 |
| user01 | visit02 | 10 |
| user02 | visit01 | 0 |
| user02 | visit02 | 5 |
| user02 | visit03 | 10 |
| user02 | visit04 | 10 |
+----------+------------+---------------+
【问题讨论】:
我删除了不一致的数据库标签。请仅使用您真正使用的数据库进行标记。 【参考方案1】:以下是 BigQuery 标准 SQL
#standardSQL
SELECT
userID,
visitID,
IFNULL(TIMESTAMP_DIFF(visitTS, LAG(visitTS) OVER(win), SECOND), 0) AS time_diff_sec,
IFNULL(TIMESTAMP_DIFF(visitTS, LAG(visitTS) OVER(win), MINUTE), 0) AS time_diff_min
FROM `project.dataset.table`
WINDOW win AS (PARTITION BY userid ORDER BY visitTS)
如果应用到您的问题中的样本数据,如下例所示
#standardSQL
WITH `project.dataset.table` AS (
SELECT 'user01' userID, 'visit01' visitID, TIMESTAMP '2019-05-13 01:00:00' visitTS UNION ALL
SELECT 'user01', 'visit02', '2019-05-13 01:10:00' UNION ALL
SELECT 'user02', 'visit01', '2019-05-13 01:05:00' UNION ALL
SELECT 'user02', 'visit02', '2019-05-13 01:10:00' UNION ALL
SELECT 'user02', 'visit03', '2019-05-13 01:20:00' UNION ALL
SELECT 'user02', 'visit04', '2019-05-13 01:30:00'
)
SELECT
userID,
visitID,
IFNULL(TIMESTAMP_DIFF(visitTS, LAG(visitTS) OVER(win), SECOND), 0) AS time_diff_sec,
IFNULL(TIMESTAMP_DIFF(visitTS, LAG(visitTS) OVER(win), MINUTE), 0) AS time_diff_min
FROM `project.dataset.table`
WINDOW win AS (PARTITION BY userid ORDER BY visitTS)
输出是
Row userID visitID time_diff_sec time_diff_min
1 user01 visit01 0 0
2 user01 visit02 600 10
3 user02 visit01 0 0
4 user02 visit02 300 5
5 user02 visit03 600 10
6 user02 visit04 600 10
【讨论】:
完美运行,谢谢。还有一个问题,如何计算 time_diff 【参考方案2】:您是否尝试过使用lag()
?。它为您提供前一行值。
对于 Bigquery,您可以使用 UNIX_SECONDS()
将时间戳转换为秒,对于 mysql,您可以使用 to_seconds()
。
select userid, visitid,
(UNIX_SECONDS(visitTS) - UNIX_SECONDS (lag(visitTS) over (partition by
userid order by userid, visitid))) as time_dif_sec
from table
【讨论】:
【参考方案3】:您可以使用窗口函数lag()
获取“上一次”访问的时间戳,然后使用日期函数。
在 MySQL 中(窗口函数仅在 8.0 版本中可用):
select
t.*,
coalesce(
to_seconds(visitTS)
- to_seconds(lag(visiTS) over(partition by userID order by visitTS),
0) ts_diff_seconds
from mytable t
在 BigQuery 中,您可以使用 timestamp_to_sec()
代替 to_seconds()
。
【讨论】:
以上是关于在 SQL 中按组中的行计算时间差异的主要内容,如果未能解决你的问题,请参考以下文章