【问题标题】:How can I reference column values from previous rows in BigQuery SQL, in order to perform operations or calculations?如何引用 BigQuery SQL 中先前行的列值,以便执行操作或计算?
【发布时间】:2019-02-15 21:52:00
【问题描述】:

我已按开始时间对数据进行了排序,我想创建一个新字段来汇总与前几行开始时间和结束时间重叠的开始时间的数据。

更具体地说,我想编写逻辑,对于给定的记录 X,如果开始时间介于前一行的开始时间和结束时间之间,我想为记录 X 赋予与新字段相同的值前一行。如果开始时间在上一行的结束时间之后,它将为新字段获取一个新值。

在 BigQuery SQL 中是否可能出现这样的情况?正在考虑可能是滞后或窗口功能,但不太确定。下面是基本表的示例以及我想要的最终表的示例。

任何见解都值得赞赏!

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    SELECT recordID, startTime, endTime,
      COUNTIF(newRange) OVER(ORDER BY startTime) AS newRecordID
    FROM (
      SELECT *, 
        startTime >= MAX(endTime) OVER(ORDER BY startTime ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS newRange
      FROM `project.dataset.table`
    )
    

    您可以使用您问题中的示例数据进行测试,使用上面的示例,如下例所示

    #standardSQL
    WITH `project.dataset.table` AS (
      SELECT 1 recordID, TIME '12:35:00' startTime, TIME '12:50:00' endTime UNION ALL
      SELECT 2, '12:46:00', '12:59:00' UNION ALL
      SELECT 3, '14:27:00', '16:05:00' UNION ALL
      SELECT 4, '15:48:00', '16:35:00' UNION ALL
      SELECT 5, '16:18:00', '17:04:00' 
    )
    SELECT recordID, startTime, endTime,
      COUNTIF(newRange) OVER(ORDER BY startTime) AS newRecordID
    FROM (
      SELECT *, 
        startTime >= MAX(endTime) OVER(ORDER BY startTime ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS newRange
      FROM `project.dataset.table`
    )
    -- ORDER BY startTime
    

    结果

    Row recordID    startTime   endTime     newRecordID  
    1   1           12:35:00    12:50:00    0    
    2   2           12:46:00    12:59:00    0    
    3   3           14:27:00    16:05:00    1    
    4   4           15:48:00    16:35:00    1    
    5   5           16:18:00    17:04:00    1    
    

    【讨论】:

    • 很好的答案,米哈伊尔,很高兴地支持这个,它帮助解决了我的挑战
    【解决方案2】:

    这是一个空白和孤岛问题。您想要做的是将组 ID 分配给不相交的组。您可以使用窗口函数计算非交叉点。

    如果结束时间的累积最大值(按开始时间排序并在前一条记录结束)小于当前结束时间,则记录开始一个新组。其余的只是分配组 id 的累积总和。

    对于您的数据:

    select t.*,
           sum(case when prev_endtime >= endtime then 0 else 1 end) over (order by starttime) as group_id
    from (select t.*,
                 max(endtime) over (order by starttime rows between unbounded preceding and 1 preceding) as prev_endtime
          from t
         ) t;
    

    唯一的潜在问题是两条记录是否同时开始。如果发生这种情况,逻辑可能需要稍微复杂一些。

    【讨论】:

    • 这太好了,谢谢。不应该有任何完全相同的开始时间戳,但我确实有不同的事件 ID - 您将如何更新语法以确保我们仅在它们遵循时间戳逻辑并且它们位于相同事件 ID 时才将它们聚集在一起.我在子查询中添加了一个“分区依据”,但效果不佳
    • @Andrew 。 . .您可以将partition by eventId 添加到窗口函数中。您的问题没有提及此类 ID。如果您不知道如何做到这一点,那么我建议您提出一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    相关资源
    最近更新 更多