【问题标题】:How to shift a year-week field in bigquery如何在 bigquery 中移动年周字段
【发布时间】:2018-06-21 17:43:16
【问题描述】:

这个问题是关于在 bigquery 中移动年-周字段的值。

run_id    year_week    value
 0001       201451       13
 0001       201452       6
 0001       201503       3
 0003       201351       8
 0003       201352       5
 0003       201403       1

在这里,每一年的一周可以从 01 到 53。例如,2014 年的最后一周是 201452,但 2015 年的最后一周是 201553。

现在我想将每个 run_id 中每个 year_week 的值移动 5 周。对于没有值的周,假定它们的值为 0。例如,上面示例表的输出应如下所示:

run_id    year_week    value
 0001       201504       13
 0001       201505       6
 0001       201506       0
 0001       201507       0
 0001       201508       3
 0003       201404       8
 0003       201405       5
 0003       201406       0
 0003       201407       0
 0003       201408       1

输出说明:在上表中,run_id0001 的 year_week201504 的值为 13,因为在输入表中,year_week201451 的值为 13,即 201504 前 5 周。

我可以通过创建从year_week 到移位year_week 的映射以编程方式创建一个表,然后进行连接以获得输出,但我想知道是否有任何其他方法可以通过使用sql.

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:
    #standardSQL
    WITH `project.dataset.table` AS (
      SELECT '001' run_id, 201451 year_week, 13 value UNION ALL
      SELECT '001', 201452, 6 UNION ALL
      SELECT '001', 201503, 3 
    ), weeks AS (
      SELECT 100 * year + week year_week
      FROM UNNEST([2013, 2014, 2015, 2016, 2017]) year, 
      UNNEST(GENERATE_ARRAY(1, IF(EXTRACT(ISOWEEK FROM DATE(1+year,1,1)) = 1, 52, 53))) week
    ), temp AS (
      SELECT i.run_id, w.year_week, d.year_week week2, value
      FROM  weeks w 
      CROSS JOIN (SELECT DISTINCT run_id FROM `project.dataset.table`) i
      LEFT JOIN `project.dataset.table` d
      USING(year_week, run_id)
    )
    SELECT * FROM (
      SELECT run_id, year_week, 
        SUM(value) OVER(win) value
      FROM temp
      WINDOW win AS (
        PARTITION BY run_id ORDER BY year_week ROWS BETWEEN 5 PRECEDING AND 5 PRECEDING
      )
    )
    WHERE NOT value IS NULL
    ORDER BY run_id, year_week
    

    结果为

    Row     run_id      year_week       value    
    1       001         201504          13   
    2       001         201505          6    
    3       001         201508          3    
    

    如果您需要“保留”零行 - 只需更改以下部分

      SELECT i.run_id, w.year_week, d.year_week week2, value
      FROM  weeks w 
    

      SELECT i.run_id, w.year_week, d.year_week week2, IFNULL(value, 0) value
      FROM  weeks w 
    

        SUM(value) OVER(win) value
      FROM temp
    

        SUM(IFNULL(value, 0)) OVER(win) value
      FROM temp
    

    【讨论】:

    • 这个答案有问题,当有多个运行时它不能正常工作,例如如果有另一个具有不同year_week和value的run_id,它们会重新出现在所有run_id中。
    • 让我检查一下 - 我认为这已经解决了 - 但没有测试,因为它不是你的示例的一部分 - 会回复你。同时 - 如果您有一个您认为给出错误结果的示例 - 请添加到您的问题中 - 如果问题得到确认,我将能够修复我的查询
    • 我明白了,很容易修复。如果您自己有问题,将很快更新
    • 可以吗?是按功能分区吗?
    • 当然,我会的。它是临时 CTE 中的 CROSS JOIN。我会尽快修复它 - 需要先处理一些事情
    【解决方案2】:

    如果您的表格中有所有年份-周的数据,那么您可以这样做:

    with yw as (
          select year_week, row_number() over (order by year_week) as seqnum
          from t
          group by year_week
         )
    select t.*, yw5, year_week as new_year_week
    from t join
         yw
         on t.year_week = yw.year_week left join
         yw yw5
         on yw5.seqnum = yw.seqnum + 5;
    

    如果您没有年周表,那么我建议您创建这样的表,以便您可以进行此类操作 - 或更通用的日历表。

    【讨论】:

    • 我有一张我考虑的所有year_weeks 的表格。效果很好,谢谢!
    • @SyedArefinulHaque 。 . .如果这可行,我很好奇你为什么选择米哈伊尔的答案?
    • 您的回答是比较通用的解决方案,有利于日后参考。但是 Mikhails 的回答更具体地针对当前情况,包含对运行 ID 的操作,并且 self 包含连接部分。
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 2023-03-12
    • 2021-10-01
    • 2018-10-15
    • 1970-01-01
    相关资源
    最近更新 更多