【问题标题】:Google BigQuery: From table of days get a table with all days of yearGoogle BigQuery:从天数表中获取一年中所有天数的表
【发布时间】:2019-07-31 06:44:10
【问题描述】:

我有这个(示例)表:

+------------+-------------------+-----------+
|    Date    |       User        | Attribute |
+------------+-------------------+-----------+
| 2019-01-01 | user1@example.com | apple     |
| 2019-02-01 | user2@example.com | pear      |
| 2019-03-01 | user1@example.com | carrot    |
| 2019-03-01 | user2@example.com | orange    |
+------------+-------------------+-----------+

我需要创建所有(日期+用户)夫妇的完整排列,以填补 2019 年所有缺失的日子(attributenull)。

就像在我的示例中一样,我有 2 个不同的用户:

  • user1@example.com
  • user2@example.com

结果表应该是:

+------------+-------------------+-----------+
|    Date    |       User        | Attribute |
+------------+-------------------+-----------+
| 2019-01-01 | user1@example.com | apple     |
| ...        | user1@example.com | null      |
| 2019-03-01 | user1@example.com | carrot    |
| ...        | user1@example.com | null      |
| 2019-12-31 | user1@example.com | null      |
| 2019-01-01 | user2@example.com | null      |
| ...        | user2@example.com | null      |
| 2019-02-01 | user2@example.com | pear      |
| ...        | user2@example.com | null      |
| 2019-03-01 | user2@example.com | orange    |
| ...        | user2@example.com | null      |
| 2019-12-31 | user2@example.com | null      |
+------------+-------------------+-----------+

... 表示一年中的每一天都有一行,当源表提供实际值时,attribute 有一个值,否则使用 null

作为第一步,创建我想到的使用bigquery-public-data.utility_eu.date_greg 表的所有(日期+用户)排列,使用CROSS JOIN 创建所有需要的行。

这里是要使用的示例表:

#standardSQL
WITH sample AS (
  SELECT DATE('2019-01-01') date, 'user1@example.com' user, 'apple' attribute
  UNION ALL
  SELECT DATE('2019-02-01'), 'user2@example.com', 'pear'
  UNION ALL
  SELECT DATE('2019-03-01'), 'user1@example.com', 'carrot'
  UNION ALL
  SELECT DATE('2019-03-01'), 'user2@example.com', 'orange'
)

这是我尝试的第一个查询:

SELECT d.date,s.* EXCEPT(date)
FROM sample s
  CROSS JOIN `bigquery-public-data.utility_eu.date_greg` d 
WHERE d.year = 2019
ORDER BY date,user

但这太多了,因为attribute 值也在联接中使用,我得到的值在与原始值无关的所有日期都被复制。

我认为我需要某种DISTINCT 才能仅获取唯一的(日期+用户)夫妇,然后才关联attribute 值(如果有)。

这是我找到的第一个可行的解决方案:

distinct_couples AS (
  SELECT DISTINCT d.date,s.user
  FROM sample s CROSS JOIN `bigquery-public-data.utility_eu.date_greg` d 
  WHERE d.year = 2019
)

SELECT d.*, s.attribute
FROM distinct_couples d
  LEFT JOIN sample s USING(date,user)
ORDER BY date,user

但我与sample 进行了两次连接(第一次在临时表中,第二次在主查询中),所以我试图了解是否可以优化。

您对如何使它起作用有什么建议吗? 谢谢

【问题讨论】:

    标签: google-bigquery cartesian-product cross-join


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    WITH users AS (
      SELECT DISTINCT user
      FROM `project.dataset.sample`
    )
    SELECT d.date, u.user, s.attribute
    FROM `bigquery-public-data.utility_eu.date_greg` d  
    CROSS JOIN users u
    LEFT JOIN `project.dataset.sample` s
    ON s.date = d.date
    AND s.user = u.user
    WHERE d.year = 2019
    

    附带说明 - 您实际上不需要使用任何额外的日期表,因为您可以即时生成它 - 如下例所示

    #standardSQL
    WITH users AS (
      SELECT DISTINCT user
      FROM `project.dataset.sample`
    ), dates AS (
      SELECT `date` 
      FROM UNNEST(GENERATE_DATE_ARRAY('2019-01-01', '2019-12-31')) `date`
    )
    SELECT d.date, u.user, s.attribute
    FROM dates d  
    CROSS JOIN users u
    LEFT JOIN `project.dataset.sample` s
    ON s.date = d.date
    AND s.user = u.user
    

    【讨论】:

    • 谢谢,我不知道GENERATE_DATE_ARRAY
    猜你喜欢
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 2017-08-19
    相关资源
    最近更新 更多