我有一个表,用于存储用户ID,会话ID和日期时间。该表存储用户登录设备时的数据,并存储用户,会话和日期时间。可以有一个用户ID和会话ID组合的多个条目。例如:
accounts
我正在尝试根据相同的会话和用户的初始datetime直到datetime + x将这些行组合到一个新表中。如果日期超过datetime + x,则初始datetime将移动。因此,如果x为30分钟,则从开始到日期时间的任何日期+ 30min都是一行。如果日期大于datetime + 30min,则它将成为新的开始日期时间,然后执行datetime + x,直到已为sessionid和userid组合查找所有日期为止。
示例表的输出应为:
{
"properties": {
"name": {
"type": "text"
},
"number": {
"type": "text"
}
}
}
我不确定如何仅使用SQL来实现。我打算创建一个存储过程来执行javascript中的所有逻辑,然后将其插入到Snowflake中的新表中,但这将非常缓慢并且无法扩展。预先感谢。
答案 0 :(得分:1)
这有点棘手。您不能只比较相邻的行:您需要跟踪每个系列行的开始日期,以便可以将其与以下日期进行比较,并确定何时分成新的组。
这需要某种迭代过程。在SQL中,通常使用递归查询来实现-幸运的是,Snowflake支持
考虑:
with recursive
data as (
select
t.*,
row_number() over(partition by userid, sessionid order by date) rn
from mytable t
),
cte as (
select
userid,
sessionid,
date start_session_date,
date end_session_date
from data
where rn = 1
union all
select
c.userid,
c.sessionid,
case when d.date > dateadd(minute, 30, c.start_session_date)
then d.date
else c.start_session_date
end,
d.date
from cte c
inner join data d
on d.userid = c.userid
and d.sessionid = c.sessionid
and d.rn = c.rn + 1 and
)
select
userid,
sessionid,
start_session_date,
max(end_session_date) end_session_date
from cte
group by userid, sessionid, start_session_date
第一个common-table-expression(data
)枚举与userid
具有相同sessionid
和row_number()
的行。然后,第二个CTE(cte
)从第一个行开始迭代遍历行的组,并根据需要创建新的组。最后一步是聚合。
答案 1 :(得分:0)
该方法利用了Snowflake WIDTH_BUCKET函数,并且根据我生成的一些测试数据似乎可以正常工作:
-- Get the min amd max timestamps for each userid, sessionid
WITH T1 AS (
SELECT USERID, SESSIONID,MIN(DATE_TIME) MIN_DATE, MAX(DATE_TIME) MAX_DATE
FROM TEST_DATA
GROUP BY USERID, SESSIONID
),
--Get the number of 'buckets', for each userid/sessionid, to divide the data into by defining the time period
--Hardcoded here as MINUTE and 30
T2 AS (
SELECT USERID, SESSIONID, MIN_DATE, MAX_DATE, CEIL(DATEDIFF(MINUTE, MIN_DATE, MAX_DATE)/30,0) NUM_BUCKETS
FROM T1
),
--Assign each record to the appropriate time period bucket
--WIDTH_BUCKET takes numeric parameters hence the conversion to epoch_seconds
T3 AS (
SELECT TD.USERID, TD.SESSIONID, TD.DATE_TIME
,width_bucket(DATE_PART(EPOCH_SECONDS,TD.DATE_TIME), DATE_PART(EPOCH_SECONDS,T2.MIN_DATE), DATE_PART(EPOCH_SECONDS,T2.MAX_DATE), T2.NUM_BUCKETS) as "TIME_GROUP"
FROM TEST_DATA TD
INNER JOIN T2 ON TD.USERID = T2.USERID AND TD.SESSIONID = T2.SESSIONID
)
--Get the min and make timestamps for each userid, sessionid and bucket combination
SELECT USERID, SESSIONID, MIN(DATE_TIME), MAX(DATE_TIME)
FROM T3
GROUP BY USERID, SESSIONID, TIME_GROUP
order BY USERID, SESSIONID, TIME_GROUP
LIMIT 10
;