获取 FIRST_VALUE 和 LAST_VALUE 之间的范围

Posted

技术标签:

【中文标题】获取 FIRST_VALUE 和 LAST_VALUE 之间的范围【英文标题】:Get range between FIRST_VALUE and LAST_VALUE 【发布时间】:2021-01-28 18:00:13 【问题描述】:
timestamp id scope
2021-01-23 12:52:34.159999 UTC 1 enter_page
2021-01-23 12:53:02.342 UTC 1 view_product
2021-01-23 12:53:02.675 UTC 1 checkout
2021-01-23 12:53:04.342 UTC 1 search_page
2021-01-23 12:53:24.513 UTC 1 checkout

我正在尝试使用 WINDOWS/ANALYTICAL 函数获取“范围”列中 FIRST_VALUE 和 LAST VALUE 之间的所有值

我已经得到了 first_value() = enter_page 和 last_value() == checkout

在 SQLite 中使用 windows 函数

FIRST_VALUE(scope) OVER ( PARTITION BY id ORDER BY julianday(timestamp) ASC) first_page
FIRST_VALUE(scope) OVER ( PARTITION BY id ORDER BY julianday(timestamp) DESC ) last_page

我正在尝试捕获 [不包括边缘] 之间的所有步骤:view_product, apartment_view, checkout[, N-field] 以便稍后将它们添加到字符串中(唯一值 -STR_AGGR() )

完成此操作后,我稍后会尝试查找客户是否在购买过程中的某个时间点多次打开结帐

我的结果应该喜欢

id first_page last_page inbetween_pages
1 enter_page checkout view_product, checkout, search_page

附言我试图避免使用 python 来处理这个。我想要一种使用纯 SQL 的“干净”方式

非常感谢大家

【问题讨论】:

【参考方案1】:

您可以使用支持ORDER BY 子句的GROUP_CONCAT() 窗口函数来执行此操作,因此您将在inbetween_pages 中以正确的顺序拥有scopes,而不是不支持的GROUP_CONCAT() 聚合函数ORDER BY 子句及其返回的结果不保证按特定顺序排列:

SELECT DISTINCT id, first_page, last_page,
       GROUP_CONCAT(CASE WHEN timestamp NOT IN (min_timestamp, max_timestamp) THEN scope END) 
       OVER (PARTITION BY id ORDER BY timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) inbetween_pages
FROM (
  SELECT *,
         FIRST_VALUE(scope) OVER (PARTITION BY id ORDER BY timestamp) first_page,
         FIRST_VALUE(scope) OVER (PARTITION BY id ORDER BY timestamp DESC) last_page,
         MIN(timestamp) OVER (PARTITION BY id) min_timestamp,
         MAX(timestamp) OVER (PARTITION BY id) max_timestamp
  FROM tablename       
)

请参阅demo。 结果:

id first_page last_page inbetween_pages
1 enter_page checkout view_product,checkout,search_page

【讨论】:

感谢您的回答,我能够解决这个问题。但是由于我只需要不同的值,因此需要进行一些小调整。我没有使用 window_functionality 而是聚合。 @OscarCopado 如果您在代码中使用了聚合函数 GROUP_CONCAT(),正如我在回答中提到的那样,您应该知道它的结果不能保证按特定顺序排列。 我知道(在运行你的小提琴示例之后)。在这种情况下,我只需要知道这个“事件”是否在某个时间点发生。非常感谢。【参考方案2】:

嗯。 . .我在想:

select id, group_concat(scope, ',')
from (select t.*,
             row_number() over (partition by id order by timestamp) as seqnum_asc,
             row_number() over (partition by id order by timestamp desc) as seqnum_desc
      from t
      order by id, timestamp
     ) t
where 1 not in (seqnum_asc, seqnum_desc)
group by id;

在 SQLite 中,group_concat() 不接受 order by 参数。我的理解是它尊重子查询的顺序,这就是子查询有order by的原因。

【讨论】:

这是解决这个 Gordon 的一个非常有趣的方法。谢谢 :) 我相信我也可以将其应用于其他查询.. 只是一个小细节,我想你错过了 seqnum_desc 部分的 DESC 部分。

以上是关于获取 FIRST_VALUE 和 LAST_VALUE 之间的范围的主要内容,如果未能解决你的问题,请参考以下文章

SQL: first_value(), 获取视频的 min_date

SQL:如何将 first_value 忽略为聚合?

(REDSHIFT) 垂直合并 / FIRST_VALUE() 作为聚合

每个用户 ID 的 first_value 和 last_value

BigQuery、FIRST_VALUE 和 null

AWS Athena 无法将 FIRST_VALUE() 识别为聚合表达式