如何根据 BigQuery 中的另一个现有行为每个用户添加记录?

Posted

技术标签:

【中文标题】如何根据 BigQuery 中的另一个现有行为每个用户添加记录?【英文标题】:How to add records for each user based on another existing row in BigQuery? 【发布时间】:2020-11-23 19:54:41 【问题描述】:

在这里发帖,以防有更多知识的人可以帮助我找到一些方向。

我有一张这样的桌子:

| Row |   date   |user id | score |
-----------------------------------
|  1  | 20201120 |  1     |   26  |
-----------------------------------
|  2  | 20201121 |  1     |   14  |
-----------------------------------
|  3  | 20201125 |  1     |   0   |
-----------------------------------
|  4  | 20201114 |  2     |   32  |
-----------------------------------
|  5  | 20201116 |  2     |   0   |
-----------------------------------
|  6  | 20201120 |  2     |   23  |
-----------------------------------

但是,据此,我需要为每个用户记录每一天,如果用户缺少一天,那么应该保留最后记录的分数,那么我会得到这样的结果:

| Row |   date   |user id | score |
-----------------------------------
|  1  | 20201120 |  1     |   26  |
-----------------------------------
|  2  | 20201121 |  1     |   14  |
-----------------------------------
|  3  | 20201122 |  1     |   14  |
-----------------------------------
|  4  | 20201123 |  1     |   14  |
-----------------------------------
|  5  | 20201124 |  1     |   14  |
-----------------------------------
|  6  | 20201125 |  1     |   0   |
-----------------------------------
|  7  | 20201114 |  2     |   32  |
-----------------------------------
|  8  | 20201115 |  2     |   32  |
-----------------------------------
|  9  | 20201116 |  2     |   0   |
-----------------------------------
|  10 | 20201117 |  2     |   0   |
-----------------------------------
|  11 | 20201118 |  2     |   0   |
-----------------------------------
|  12 | 20201119 |  2     |   0   |
-----------------------------------
|  13 | 20201120 |  2     |   23  |
-----------------------------------

我正在尝试使用 StandardSQL 在 BigQuery 中完成此操作。我知道如何在以下空日期中保持相同的分数,但我真的不知道如何为每个用户的缺失日期添加新行。另外,请记住,这个例子只有 2 个用户,但在我的数据中我有超过 1500 个。

我的最终目标是显示每天的平均得分。作为背景,由于我们的逻辑,如果分数不是在特定日期记录的,这意味着用户仍然在最后记录的分数中,这就是为什么我需要每天为每个用户记录一个分数。

如果能得到任何帮助,我将不胜感激!我一直在尝试不同的选择,但没有成功

【问题讨论】:

有一个日历帮助表/cte。外连接。 我如何为每个用户添加它?我已经这样做了,但是我不知道如何确保我为每个用户添加丢失的日期不只是一次 【参考方案1】:

以下是 BigQuery 标准 SQL

#standardSQL
select date, user_id, 
  last_value(score ignore nulls) over(partition by user_id order by date) as score
from (
  select user_id, format_date('%Y%m%d', day) date,  
  from (
    select user_id, min(parse_date('%Y%m%d', date)) min_date, max(parse_date('%Y%m%d', date)) max_date
    from `project.dataset.table` 
    group by user_id
  ) a, unnest(generate_date_array(min_date, max_date)) day
)
left join `project.dataset.table` b
using(date, user_id)
-- order by user_id, date     

如果应用于您问题的样本数据 - 输出是

【讨论】:

【参考方案2】:

一个选项使用generate_date_array() 创建每个用户的一系列日期,然后使用left join 带来表格。

select d.date, d.user_id, 
    last_value(t.score ignore nulls) over(partition by d.user_id order by d.date) as score
from (
    select t.user_id, d.date
    from mytable t
    cross join unnest(generate_date_array(min(date), max(date), interval 1 day)) d(date)
    group by t.user_id
) d
left join mytable t on t.user_id = d.user_id and t.date = d.date

【讨论】:

【参考方案3】:

我认为最有效的方法是使用generate_date_array(),但方式非常特殊:

with t as (
      select t.*,
             date_add(lead(date) over (partition by user_id order by date), interval -1 day) as next_date
      from t
     )
select row_number() over (order by t.user_id, dte) as id,
       t.user_id, dte, t.score
from t cross join join
     unnest(generate_date_array(date,
                                coalesce(next_date, date)
                                interval 1 day
                               )
           ) dte;

【讨论】:

以上是关于如何根据 BigQuery 中的另一个现有行为每个用户添加记录?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 bigquery 中的另一个表中获取短语列表的表字段中的匹配计数?

如何在 SQL Bigquery 中的另一个事件之前计算特定事件的数量?

如果一个数组包含使用 BigQuery 的另一个数组的所有值,我如何过滤行?

如何覆盖 bigquery 现有表中的列值

如何通过 BigQuery 中的 WebUI 导出现有表的架构?

使用现有 JSON 文件,如何将此数据上传到 BigQuery 并使用 JSON 文件中的数据计算新字段?