Sql 如何将日期分成24小时组-BigQuery

Sql 如何将日期分成24小时组-BigQuery,sql,google-bigquery,window-functions,Sql,Google Bigquery,Window Functions,这是我的目标,将日期分成24小时一组,但这取决于数据,而不是非常具体的日期 假设这些是来自呼叫中心的呼叫,我想知道我有多少个会话,但这些会话在24小时内有效,这24小时从第一个发送日期开始计算,如果下一个呼叫在前24小时之后,将创建一个新会话 预期结果如下: 前3列是我在表中已有的,第四列是所需的计算 identifier customer_id date_sent StartOfSession sessionId 456456150 5366

这是我的目标,将日期分成24小时一组,但这取决于数据,而不是非常具体的日期


假设这些是来自呼叫中心的呼叫,我想知道我有多少个会话,但这些会话在24小时内有效,这24小时从第一个发送日期开始计算,如果下一个呼叫在前24小时之后,将创建一个新会话

预期结果如下: 前3列是我在表中已有的,第四列是所需的计算

identifier  customer_id date_sent               StartOfSession          sessionId
456456150   5366    2020-09-01T10:17:48.360000  2020-09-01T10:17:48.360000  1
456456150   5366    2020-09-01T18:24:45.552000  2020-09-01T10:17:48.360000  1
456456150   5366    2020-09-02T10:20:46.283000  2020-09-02T10:20:46.283000  2
456456150   5366    2020-09-02T18:25:01.911000  2020-09-02T10:20:46.283000  2
456456150   5366    2020-09-03T10:20:38.407000  2020-09-02T10:20:46.283000  2
456456150   5366    2020-09-03T18:23:35.915000  2020-09-03T18:23:35.915000  3
456456150   5366    2020-09-04T10:19:46.474000  2020-09-03T18:23:35.915000  3
456456150   5366    2020-09-04T14:22:17.236000  2020-09-03T18:23:35.915000  3
456456150   5366    2020-09-04T18:24:33.155000  2020-09-04T18:24:33.155000  4
456456150   5366    2020-09-05T10:19:48.871000  2020-09-04T18:24:33.155000  4
456456150   5366    2020-09-05T18:25:07.968000  2020-09-05T18:25:07.968000  5
456456150   5366    2020-09-06T10:19:34.808000  2020-09-05T18:25:07.968000  5
456456150   5366    2020-09-06T18:26:17.705000  2020-09-06T18:26:17.705000  6
456456150   5366    2020-09-07T10:21:28.585000  2020-09-06T18:26:17.705000  6
456456150   5366    2020-09-07T18:24:17.123000  2020-09-06T18:26:17.705000  6
456456150   5366    2020-09-08T10:20:09.850000  2020-09-08T10:20:09.850000  7
456456150   5366    2020-09-08T18:24:32.733000  2020-09-08T10:20:09.850000  7
456456150   5366    2020-09-09T10:20:05.336000  2020-09-08T10:20:09.850000  7
456456150   5366    2020-09-09T12:12:41.137000  2020-09-09T12:12:41.137000  8
456456150   5366    2020-09-09T18:24:25.783000  2020-09-09T12:12:41.137000  8
我尝试过使用窗口函数,但无法获得相同的预期结果:

  SELECT identifier, customer_id, date_sent,
    FIRST_VALUE(date_sent) OVER (PARTITION BY A.identifier, A.customer_id, CAST(A.date_sent AS DATE) ORDER BY UNIX_SECONDS(TIMESTAMP(date_sent)) RANGE BETWEEN 86400 PRECEDING AND CURRENT ROW) FirstV_date1
  FROM `sandbox.testing` A
  WHERE identifier = '456456150'
AND date_sent between '2020-09-01' AND '2020-09-10'
这就是我的实际结果

identifier  customer_id date                    FirstV_date1
456456150   5366    2020-09-01T10:17:48.360000  2020-09-01T10:17:48.360000
456456150   5366    2020-09-01T18:24:45.552000  2020-09-01T10:17:48.360000
456456150   5366    2020-09-02T10:20:46.283000  2020-09-02T10:20:46.283000
456456150   5366    2020-09-02T18:25:01.911000  2020-09-02T10:20:46.283000
456456150   5366    2020-09-03T10:20:38.407000  2020-09-03T10:20:38.407000
456456150   5366    2020-09-03T18:23:35.915000  2020-09-03T10:20:38.407000
456456150   5366    2020-09-04T10:19:46.474000  2020-09-04T10:19:46.474000
456456150   5366    2020-09-04T14:22:17.236000  2020-09-04T10:19:46.474000
456456150   5366    2020-09-04T18:24:33.155000  2020-09-04T10:19:46.474000
456456150   5366    2020-09-05T10:19:48.871000  2020-09-05T10:19:48.871000
456456150   5366    2020-09-05T18:25:07.968000  2020-09-05T10:19:48.871000
456456150   5366    2020-09-06T10:19:34.808000  2020-09-06T10:19:34.808000
456456150   5366    2020-09-06T18:26:17.705000  2020-09-06T10:19:34.808000
456456150   5366    2020-09-07T10:21:28.585000  2020-09-07T10:21:28.585000
456456150   5366    2020-09-07T18:24:17.123000  2020-09-07T10:21:28.585000
456456150   5366    2020-09-08T10:20:09.850000  2020-09-08T10:20:09.850000
456456150   5366    2020-09-08T18:24:32.733000  2020-09-08T10:20:09.850000
456456150   5366    2020-09-09T10:20:05.336000  2020-09-09T10:20:05.336000
456456150   5366    2020-09-09T12:12:41.137000  2020-09-09T10:20:05.336000
456456150   5366    2020-09-09T18:24:25.783000  2020-09-09T10:20:05.336000
我也尝试过使用self-join,但我更愿意使用self-join,这不是因为它非常昂贵,但是,任何想法都是受欢迎的


提前谢谢

下面是BigQuery标准SQL假设date_sent列是时间戳数据类型-如提供的示例所示

#standardSQL
create temp function get_sessions(x array<timestamp>)
returns array<struct<date_sent timestamp, sessionStart timestamp, session string>>
language js as """
  output = []; session = 1; sessionStart = x[0]; total_dur = 0;  
  a = {}; a.date_sent = x[0]; a.session = session; a.sessionStart = sessionStart;
  output.push(a);
  for(i = 1; i < x.length; i++){
    a = {};
    total_dur += x[i].getTime() - x[i-1].getTime();
    if(total_dur>24*3600*1000){
      total_dur = 0; session++; sessionStart = x[i];  
    };
    a.date_sent = x[i-1]; a.sessionStart = sessionStart; a.session = session;
    output.push(a);
  }
  return output;
""";
select identifier, customer_id, date_sent, sessionStart, session
from (
  select identifier, customer_id, get_sessions(array_agg(date_sent order by date_sent)) sessions
  from `project.dataset.table`
  group by identifier, customer_id
), unnest(sessions)
如果要应用于问题中的样本数据-输出为


重要提示:此处的假设-根据您的评论-每个分区标识符的行数,客户id相对较小~2K,因此js udf内存限制在此处不是问题

以下是BigQuery标准SQL假设date_sent列为时间戳数据类型-如提供的示例所示

#standardSQL
create temp function get_sessions(x array<timestamp>)
returns array<struct<date_sent timestamp, sessionStart timestamp, session string>>
language js as """
  output = []; session = 1; sessionStart = x[0]; total_dur = 0;  
  a = {}; a.date_sent = x[0]; a.session = session; a.sessionStart = sessionStart;
  output.push(a);
  for(i = 1; i < x.length; i++){
    a = {};
    total_dur += x[i].getTime() - x[i-1].getTime();
    if(total_dur>24*3600*1000){
      total_dur = 0; session++; sessionStart = x[i];  
    };
    a.date_sent = x[i-1]; a.sessionStart = sessionStart; a.session = session;
    output.push(a);
  }
  return output;
""";
select identifier, customer_id, date_sent, sessionStart, session
from (
  select identifier, customer_id, get_sessions(array_agg(date_sent order by date_sent)) sessions
  from `project.dataset.table`
  group by identifier, customer_id
), unnest(sessions)
如果要应用于问题中的样本数据-输出为


重要提示:此处假设-根据您的评论-每个分区标识符的行数,customer_id相对较小~2K,因此js udf内存限制在这里不是问题

您的表中有多少行?请在前1行和后1行之间进行尝试该表将有1亿行,这就是为什么我也不使用自连接,我在前面使用了86400,因为日期已转换为UNIX时间,86400=24小时。很抱歉,我错过了。你能用通俗易懂的英语向我解释一下预期结果背后的逻辑吗?假设这些是呼叫中心的电话,我想知道我有多少个会话,但这些会话在24小时内有效,这24小时从你发送的第一个日期开始算起,如果下一个呼叫在前24小时之后,将创建一个新会话我编辑了帖子,我希望更清楚您的表中有多少行?在1行和1行之间进行尝试该表将有1亿行,这就是为什么我也不想使用自连接,我使用86400行,因为日期已转换为UNIX时间,86400=24小时。很抱歉,我错过了这一点。你能用通俗易懂的英语向我解释一下预期结果背后的逻辑吗?假设这些是呼叫中心的电话,我想知道我有多少个会话,但这些会话在24小时内有效,这24小时从你发送的第一个日期开始算起,如果下一个呼叫在前24小时之后,我编辑了这篇文章,我希望能说得更清楚。我知道上面说的是避免感谢,但这对我帮助很大,我想指出这一点。谢谢我知道上面说要避免感谢,但这对我帮助很大,我想指出这一点。谢谢